hujiangtech.github.io/tech/android/2017/06/02/swiftvskotlin–control–flow.html
感受一下:
// Switch case
var id = 5;
switch (id) {
case 1:
print("id == 1");
break;
case 2:
print("id == 2");
break;
default:
print("id is undefined");
}
// Inclusive for loop
for (var i = 1; i <= 5; i++) {}
// range match
// N/A
// Cascade notation (…)
querySelector(‘#confirm’)
…text = ‘Confirm’
…classes.add(‘important’)
…onClick.listen((e) =>
window.alert(‘Confirmed!’));
// When
val id = 5
when (id) {
1 -> print("id == 1")
2 -> print("id == 2")
else -> {
print("id is undefined")
}
}
// Inclusive for loop
for (index in 1..5) {}
// range match
val nb = 42
when (nb) {
in 0..7, 8, 9 -> println(“single digit”)
10 -> println(“double digits”)
in 11..99 -> println(“double digits”)
in 100..999 -> println(“triple digits”)
else -> println(“four or more digits”)
}
// Cascade notation (…)
// N/A,可以用 Builder 模式或者 apply, also 函数
// Switch case
let id = 5
switch id {
case 1:
print("id == 1")
case 2:
print("id == 2")
default:
print("id is undefined")
}
// Inclusive for loop
for index in 1.…5 {}
// range match
let nb = 42
switch nb {
case 0.…7, 8, 9: print(“single digit”)
case 10: print(“double digits”)
case 11.…99: print(“double digits”)
case 100.…999: print(“triple digits”)
default: print(“four or more digits”)
}
// Cascade notation (…)
// N/A,用 Builder 或者 apply{} 扩展
总结:Kotlin,Swift 的控制流都各有许多减少代码量,增加代码清晰度的花样。比如 Kotlin 用增强版的 when 取代了 switch ,if 和 when 不仅可做控制语句,也可作表达式使用。Swift 的 switch 语句支持元组,where 语句添加额外判断等。
Dart 的 switch 跟 Java 一样,需要主动 break,Swift 则相反,匹配到则自动退出 switch ,想要显式继续执行的话要用 fallthrough 。
Dart 的级联注记 (Cascade notation) 也算它的一个小特色了,不过其他语言也有各自的替代方案。严格说来,它并不算一个操作符,只是 Dart 的一种特殊语法。笔者自己在写 Java 代码时也封装 API 做过类似的操作。这种书写方式最大的好处是:把一堆高度相关的代码逻辑“强制”聚在一处,使代码看起来更流畅,整洁。
函数
Dart
String greet(String name, String day) {
return "Hello $name, today is $day.";
}
greet("Bob", "Tuesday");
Kotlin
fun greet(name: String, day: String): String {
return "Hello $name, today is $day."
}
greet("Bob", "Tuesday")
func greet(_ name: String, _ day: String) -> String {
return "Hello (name), today is (day)."
}
greet("Bob", "Tuesday")
总结:Swift 和 Kotlin 都是类型后置的风格,注意 Swift 返回值用 -> , Kotlin 仍是用冒号。
下划线在 Swift 中有许多用法,其中有一类主要是“忽略”,包括忽略元组元素,循环的局部变量,以及函数中的外部参数名。Standard Library 中有大量 API 的第一个参数都是可以忽略外部参数名的。
Kotlin 用 fun,Swift 用 func,Dart 和 Java ,C 等语言一样,没有为函数声明引入额外的关键字。
Dart
N/A
Kotlin
fun sumOf(vararg numbers: Int): Int {
var sum = 0
for (number in numbers) {
sum += number
}
return sum
}
sumOf(42, 597, 12)
一个 Kotlin 函数只能有一个可变数量的参数。对于顺序,没有强制约束,可以放在普通参数之前或者之后。当同时包含可变参数和普通参数时,调用时普通参数需要使用命名参数的调用语法。
fun sumOfNumbers(vararg numbers: Double, initialSum: Double): Double {
var sum = initialSum
for(number in numbers) {
sum += number
}
return sum
}
sumOfNumbers(1.5, 2.5, initialSum=100.0) // Result = 104.0
Swift
func sumOf(_ numbers: Int...) -> Int {
var sum = 0
for number in numbers {
sum += number
}
return sum
}
sumOf(42, 597, 12)
可变数量的参数在 Swift 官方文档中称为 variadic parameter 。同样,一个函数只允许至多一个 variadic parameter 。
函数类型
Dart
// 写法2
int Function(int) makeIncrementer2(int a) {
int myInnerFunction(a) {
return 1 + a;
}
<span class="kd">final</span> <span class="n">myFunction</span> <span class="o">=</span> <span class="n">myInnerFunction</span><span class="p">;</span>
<span class="k">return</span> <span class="n">myFunction</span><span class="p">;</span>
}
// 写法3:类型是 Closure: (int) => int
int Function(int) increment = (int a) {
return 1 + a;
};
// 写法4:类型是 Closure: (dynamic) => num
var increment2 = (a) {
return 1 + a;
};
print(makeIncrementer);
print(makeIncrementer(1));
print(makeIncrementer(1)());
print(increment);
print(increment(1));
Kotlin
fun makeIncrementer(): (Int) -> Int {
val addOne = fun(number: Int): Int {
return 1 + number
}
return addOne
}
val increment = makeIncrementer()
increment(7)
// makeIncrementer 可以写成更短的形式
fun makeIncrementer2() = fun(number: Int) = 1 + number
Swift
func makeIncrementer() -> (Int -> Int) {
func addOne(number: Int) -> Int {
return 1 + number
}
return addOne
}
let increment = makeIncrementer()
increment(7)
总结:在这几种语言中,函数都是一等公民。Swift 是中规中矩的写法,Kotlin 提供了简短的版本。Dart 也有几种写法。当然,写法 1、2 和写法 3 、4 并不对等,推荐 3、4 的写法。留意结尾的分号,这里有没有分号结尾的差别类似于 C++ 中的声明和定义。写法1、2 仅声明,写法 3、4 声明的同时也定义了,所以必须加分号。
Dart
// 写法1
numbers.map((number) => 3 * number).toList();
// 写法2:类似 Python 的语法
[for (var number in numbers) 3 * number];
Kotlin
Swift
let numbers = [20, 19, 7, 12]
numbers.map { 3 * $0 }
Dart
Kotlin
Swift
命名参数
Dart
area(width: 2, height: 3)
// 命名参数可以按任意顺序书写
area(height: 3, width: 2)
// Dart 的可选顺序参数,用 [] 包裹
int area([int width, int height]) {
return width * height;
}
area(); // 可编译,运行时错误
area(2); // 可编译,运行时错误
area(2, 3); // OK
Kotlin
// 混合顺序参数和命名参数的写法
area(2, height = 3)
// 全部采用命名参数时可以按任意顺序书写
area(height = 3, width = 2)
Swift
总结:Swift 的参数列表设计最为严格,参数需要同时匹配顺序和名称 (命名的作用仅仅只是为了使代码含义更清晰) 。Kotlin 类似 Python,纯命名参数方式可以随意调整顺序,意味着开发者记忆 API 不需要记顺序。 Dart 的命名参数同时也是可选参数。
类
Dart
class Shape {
var numberOfSides = 0;
String simpleDescription() {
return "A shape with $numberOfSides sides.";
}
}
var shape = Shape();
shape.numberOfSides = 7;
var shapeDescription = shape.simpleDescription();
Kotlin
class Shape {
var numberOfSides = 0
fun simpleDescription() =
"A shape with $numberOfSides sides."
}
var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()
Swift
class Shape {
var numberOfSides = 0
func simpleDescription() -> String {
return "A shape with (numberOfSides) sides."
}
}
var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()
Dart
class NamedShape {
int numberOfSides = 0;
String name;
<span class="n">NamedShape</span><span class="p">(</span><span class="kt">String</span> <span class="n">name</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">// 或者采用语法糖写法
<span class="kt">String</span> <span class="n">simpleDescription</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="s2">"A shape with </span><span class="si">$</span><span class="n">numberOfSides</span><span class="s2"> sides."</span><span class="p">;</span>
<span class="p">}</span>
}
class Square extends NamedShape {
double sideLength;
<span class="n">Square</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="n">sideLength</span><span class="p">,</span> <span class="kt">String</span> <span class="n">name</span><span class="p">)</span> <span class="o">:</span> <span class="k">super</span><span class="p">(</span><span class="n">name</span><span class="p">)</span> <span class="p">{</span>
<span class="n">numberOfSides</span> <span class="o">=</span> <span class="m">4</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">double</span> <span class="n">area</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">sideLength</span> <span class="o">*</span> <span class="n">sideLength</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">// Dart 官方建议审慎使用 @override 注解,当超类不在自身控制下时使用
// 这个注解主要是为了超类更改了代码,子类不知情仍正常工作时可以提醒程序员
@override
String simpleDescription() {
return “A square with sides of length $sideLength.”;
}
}
final test = Square(;5.2, “square”);
print(test.area());
print(test.simpleDescription());
Kotlin
open class NamedShape(val name: String) {
var numberOfSides = 0
<span class="k">open</span> <span class="k">fun</span> <span class="nf">simpleDescription</span><span class="p">()</span> <span class="p">=</span>
<span class="s">"A shape with $numberOfSides sides."</span>
}
class Square(var sideLength: BigDecimal, name: String) :
NamedShape(name) {
init {
numberOfSides = 4
}
<span class="k">fun</span> <span class="nf">area</span><span class="p">()</span> <span class="p">=</span> <span class="n">sideLength</span><span class="p">.</span><span class="n">pow</span><span class="p">(</span><span class="m">2</span><span class="p">)</span>
<span class="k">override</span> <span class="k">fun</span> <span class="nf">simpleDescription</span><span class="p">()</span> <span class="p">=</span>
<span class="s">"A square with sides of length $sideLength."</span>
}
val test = Square(BigDecimal(“5.2”), “square”)
println(test.area())
println(test.simpleDescription())
Swift
class NamedShape {
var numberOfSides: Int = 0
let name: String
<span class="kd">init</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="nb">String</span><span class="p">)</span> <span class="p">{</span>
<span class="kc">self</span><span class="p">.</span><span class="n">name</span> <span class="p">=</span> <span class="n">name</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">simpleDescription</span><span class="p">()</span> <span class="p">-&gt;</span> <span class="nb">String</span> <span class="p">{</span>
<span class="k">return</span> <span class="s">"A shape with </span><span class="si">(</span><span class="n">numberOfSides</span><span class="si">)</span><span class="s"> sides."</span>
<span class="p">}</span>
}
class Square: NamedShape {
var sideLength: Double
<span class="kd">init</span><span class="p">(</span><span class="n">sideLength</span><span class="p">:</span> <span class="nb">Double</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">String</span><span class="p">)</span> <span class="p">{</span>
<span class="kc">self</span><span class="p">.</span><span class="n">sideLength</span> <span class="p">=</span> <span class="n">sideLength</span>
<span class="kc">super</span><span class="p">.</span><span class="kd">init</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="n">name</span><span class="p">)</span>
<span class="kc">self</span><span class="p">.</span><span class="n">numberOfSides</span> <span class="p">=</span> <span class="mi">4</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">area</span><span class="p">()</span> <span class="p">-&gt;</span> <span class="nb">Double</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">sideLength</span> <span class="o">*</span> <span class="n">sideLength</span>
<span class="p">}</span>
<span class="kr">override</span> <span class="kd">func</span> <span class="nf">simpleDescription</span><span class="p">()</span> <span class="p">-&gt;</span> <span class="nb">String</span> <span class="p">{</span>
<span class="k">return</span> <span class="s">"A square with sides of length "</span> <span class="o">+</span>
<span class="nb">String</span><span class="p">(</span><span class="n">sideLength</span><span class="p">)</span> <span class="o">+</span> <span class="s">"."</span>
<span class="p">}</span>
}
let test = Square(sideLength: 5.2, name: “square”)
print(test.area())
print(test.simpleDescription())
总结:继承的书写方式在各种编程语言中可谓五花八门。像 Python 是将父类放在 () 里紧跟在子类名后,Ruby 是用 < 。典型的 C 家族是用 :。现代编程语言主要在构造器上玩一些花样。其中 Kotlin 的花样特别多,分为主从两类构造器,主构造器必有 (没声明的话会默认生成无参的 public 主构造器) ,主构造器隐含初始化块等。写法上主构造器是直接跟在类头。
// Kotlin
class NamedShape constructor(val name: String) { /*……*/ }
// 如果主构造函数没有任何注解或者可见性修饰符,可以省略这个 constructor 关键字。
关于
override ,个人更喜欢 Kotlin 和 Swift 把它们作为关键字的做法。这样在编译期就能够明确开发者的意图。其一避免本不想重写但不小心重写的情况,其二显式书写确保重写的方法存在,即正确重写了。
Dart
final test = Square(5.2, "square");
if (test is Square) {
print("test is square.");
}
if (test is! Square) {
print(“test is not square.”);
}
// 获取类型
print(test.runtimeType);
Kotlin
val test = Square(BigDecimal("5.2"), "square")
if (test is Square) {
println("test is square.")
}
if (test !is Double) {
println("test is not square.")
}
// 获取类型
println(test.javaClass.kotlin);
Swift
let test = Square(sideLength: 5.2, name: "square")
if (test is Square) {
print("test is square.")
}
if !(test is Double) {
print("test is not square.")
}
// 获取类型
print(type(of: test));
Dart
// 被声明为 abstract 因此不能被实例化
abstract class AbstractContainer {
// 定义构造器, 字段, 方法...
void updateChildren(); // Abstract method.
}
// Dart 移除了显式接口声明,
// 每个类都隐式的定义个了一个包含该类和该类实现的接口的所有实例成员
// (说人话:类就是接口)。
// 一个类通过 implements 语句声明它们实现一个或者多个接口,
// 然后提供接口要求的 API,例如:
// Person. 包含了 greet() 方法的隐式接口
class Person {
// 仅库可见,属于接口的一部分
final _name;
<span class="c1">// 不属于接口的一部分,因为这是个构造器
<span class="c1">// 属于接口的一部分
String greet(String who) => ‘Hello,
<
/
s
p
a
n
>
<
s
p
a
n
c
l
a
s
s
=
”
n
”
>
w
h
o
<
/
s
p
a
n
>
<
s
p
a
n
c
l
a
s
s
=
”
s
1
”
>
.
I
a
m
<
/
s
p
a
n
>
<
s
p
a
n
c
l
a
s
s
=
”
s
i
”
>
</span><span class=”n”>who</span><span class=”s1″>. I am </span><span class=”si”>
</span><spanclass=“n“>who</span><spanclass=“s1″>.Iam</span><spanclass=“si“>_name.’;
}
// 一个 Person 接口的实现
class Impostor implements Person {
get _name => ‘’;
<span class="kt">String</span> <span class="n">greet</span><span class="p">(</span><span class="kt">String</span> <span class="n">who</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="s1">'Hi </span><span class="si">$</span><span class="n">who</span><span class="s1">. Do you know who I am?'</span><span class="p">;</span>
}
String greetBob(Person person) => person.greet(‘Bob’);
void main() {
print(greetBob(Person(‘Kathy’)));
print(greetBob(Impostor()));
}
// 如果想要像 Java 那样的接口,建议用抽象类作为接口,相当于是把关心的部分提炼出来
Kotlin
interface Nameable {
fun name(): String
}
fun <T: Nameable> f(x: T) {
println(“Name is “ + x.name())
}
class NameX : Nameable {
override fun name() : String {
return “NameX”;
}
}
f(x = NameX())
Swift
protocol Nameable {
func name() -> String
}
func f<T: Nameable>(x: T) {
print(“Name is “ + x.name())
}
class NameX: Nameable {
func name() -> String {
return “NameX”;
}
}
f(x: NameX())
Lambda 表达式、闭包
lambda 表达式,简单理解为匿名函数,它是“函数字面值”,即未声明的函数, 但立即做为表达式传递。闭包,简单理解为持有外部环境变量的函数。两者都是函数,并非所有的匿名函数都是闭包,也并非所有的闭包都是匿名的。
Dart
// 匿名函数标准形式
// ([[Type] param1[, …]]) {
// codeBlock;
// };
var list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
print('${list.indexOf(item)}: $item');
});
Kotlin
// 拖尾 lambda 表达式
// 如果函数的最后一个参数是函数,那么作为相应参数传入的 lambda 表达式可以放在圆括号之外:
val product = items.fold(1) { acc, e -> acc * e }
// 唯一参数 lambda 表达式
// 如果该 lambda 表达式是调用时唯一的参数,那么圆括号可以完全省略:
run { println(“…”) }
Swift
// 闭包表达式标准形式
// { (parameters) -> return type in
// statements
// }
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
return s1 > s2
})
// 拖尾闭包
// 如果函数的最后一个参数是函数,那么作为相应参数传入的闭包表达式可以放在圆括号之外:
reversedNames = names.sorted() { $0 > $1 }
// 唯一参数闭包
// 如果该闭包是调用时唯一的参数,那么圆括号可以完全省略
reversedNames = names.sorted { $0 > $1 }
原文地址:https://blog.csdn.net/weixin_43959963/article/details/128643755
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_41790.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!