美文网首页我爱编程
Swift vs. Kotlin 漫谈之控制流

Swift vs. Kotlin 漫谈之控制流

作者: wishing111 | 来源:发表于2017-07-03 22:18 被阅读0次

    Kotlin 君和 Swift 君在一个团队一起开发已经很久了,由于平台的差异性,他们经常会进行一些技术上的交流(PK),「Kotlin vs. Swift」系列就是他们在互相切磋时的语录。

    技术漫谈

    Kotlin:

    Hi,Swift 君,今天我们继续煮酒论道吧

    Swift:

    好,那我们今天就切磋一下控制流吧, 你们是怎么做条件判断的?

    Kotlin:

    我们用 if 做条件判断,一般传统的形式是这样的:

    var max: Int
    if (a > b) {
        max = a
    } else {
        max = b
    }
    

    Swift:

    嗯,这与我们一样,我们可以省略 if 后面的小括号 ()

    Kotlin:

    但是我们 if 语句可以用作表达式,可以有值返回,如 val b = if (a > 0) a else 0

    Swift:

    这也没啥,与我们的三目运算符如出一辙,var b = a > 0 ? a : 0
    半斤八两,没啥好炫耀的.

    Kotlin:

    额。。。好吧,那我们 if 做表达式的时候后面也可以接代码块,在块代码中随后一行的输出会作为该块代码的返回值,如下:

    val max = if (a > b) {
        print("Choose a")
        a
    } else {
        print("Choose b")
        b
    }
    

    你行吗?

    Swift:

    这。。。,算你牛×

    Kotlin:

    哈哈,服了吧,需要注意的是,if 在用作表达式的时候,后面必须提供 else 从句。

    Swift:

    哦,我们的 if 语句和大多数语言类似,没有啥花哨的东西,但是我们除了 if 做条件判断外,还可以用 guard 语句, 形式如下:

    guard <condition> else {
        <statements>
    }
    
    

    Kotlin:

    这看着和 if 语句差不多嘛,有啥区别呢?

    Swift:

    举个栗子你就明白了

    if 版本:
    func greet(person: [String: String]) {
        if let name = person["name"] {
            print("Hello \(name)")
            
            if let location = person["location"] {
                print("weather is nice in \(location).")
            } else {
                print("weather is nice near you.")
            }
        } else {
            print("Hello stranger")
        }
    }
    
    guard 版本:
    func greet(person: [String: String]) {
        guard let name = person["name"] else {
            print("Hello stranger")
            return
        }
        
        print("Hello \(name)")
        
        guard let location = person["location"] else {
            print("weather is nice near you.")
            return
        }
        
        print("weather is nice in \(location).")
    }
    
    

    对比可以看出,guard 版本更清晰易读,if 版本的一连串的 if/else 让人头晕。

    Kotlin:

    赞,说白了,guard 就是把不符合条件的处理事件前置,提前退出,避免了代码金字塔的出现,使代码看起来更优雅,更易读。不过跟你说个小秘密,我们自己封装个类似 guard 的函数。

    Swift:

    2333,不过我们使用 guard 语句的时候也必须要有 else 从句

    Kotlin:

    嗯嗯,来说说你们是怎么做条件匹配的

    Swift:

    我们用 switch 语句来进行条件匹配,例如:

    let x = 1
    
    switch x {
    case 1:
        print("x == 1")
    case 2:
        print("x == 2")
    default:
        print("x is neither 1 nor 2")
    }
    
    

    Kotlin:

    差不多,我们是用 when 来进行条件匹配,意思是一样的:

    when (x) {
        1 -> print("x == 1")
        2 -> print("x == 2")
        else -> { // 注意这个块
            print("x is neither 1 nor 2")
        }
    }
    

    Swift:

    嗯~ o(* ̄▽ ̄*)o,语法不一样而已,看上去你们的更简洁一些嘛。

    Kotlin:

    当有不同的分支需要同样的处理的话,可以用逗号分隔写在一起。

    when (x) {
        0, 1 -> print("x == 0 or x == 1")
        else -> print("otherwise")
    }
    

    Swift:

    我的写法也一样:

    switch x {
    case 0, 1:
        print("x == 0 or x == 1")
    default:
        print("otherwise")
    }
    
    

    当匹配到的 case 中的代码执行完毕后,switch 语句会直接退出,而不会继续执行下一个 case ,如果确实想执行下一个 case,我们也提供了相应的方法。

    Kotlin:

    这也可以?什么方法?

    Swift:

    就是显式的在当前 case 中使用 fallthrough 语句。例如:

    let x = 5
    var description = "\(x) is"
    switch x {
    case 2, 3, 5, 7, 11:
        description += " a prime number, and also"
        fallthrough
    default:
        description += " an integer."
    }
    print(description)
    // 输出 "5 is a prime number, and also an integer."
    
    

    Kotlin:

    我们没有这个功能,不过这种贯穿功能似乎也不常用嘛。

    Swift:

    是的,不常用不代表没有用嘛。switch 还可以匹配一个值的区间。例如:

    switch x {
    case 1..<10:
        print("single digit")
    case 10...99:
        print("double digit")
    default:
        print("out of range")
    }
    
    

    Kotlin:

    when 也可以:

    when (x) {
        in 1..10 -> print("x is in the range")
        in validNumbers -> print("x is valid")
        !in 10..20 -> print("x is outside the range")
        else -> print("none of the above")
    }
    
    

    Swift:

    哇~, 你们还可以直接在一个匹配模式之前加 ! 操作符,好强大,我们不可以。

    Kotlin:

    牛吧,不仅如此,when 可以不提供参数,直接顺序匹配满足条件的表达式后,执行其对应后面的表达式。

    when {
        x.isOdd() -> print("x is odd")
        x.isEven() -> print("x is even")
        else -> print("x is funny")
    }
    
    

    Swift:

    厉害了,我们不行,我们 switch 后必须要有参数。

    Kotlin:

    哈哈,服了吧

    Swift:

    不服,看来不给你点厉害的瞧瞧,不知道马王爷有几只眼!

    Kotlin:

    (⊙ˍ⊙)

    Swift:

    我们可以使用元组在同一个 switch 语句中测试多个值。元组中的元素可以是值,也可以是区间。另外,可以使用下划线(_)来匹配所有可能的值。例如:

    let somePoint = (1, 1)
    switch somePoint {
    case (0, 0):
        print("(0, 0) is at the origin")
    case (_, 0):
        print("(\(somePoint.0), 0) is on the x-axis")
    case (0, _):
        print("(0, \(somePoint.1)) is on the y-axis")
    case (-2...2, -2...2):
        print("(\(somePoint.0), \(somePoint.1)) is inside the box")
    default:
        print("(\(somePoint.0), \(somePoint.1)) is outside of the box")
    }
    // 输出 "(1, 1) is inside the box"
    
    

    Kotlin:

    赞!我们没有元组类型,虽然 Kotlin 也提供了类似的析构功能,但还是没有你们这么灵活,所以也就没有这种模式匹配。

    Swift:

    不仅如此,case 分支还允许将匹配的值绑定到一个临时的常量或变量,并且在 case 分支体内使用:

    let anotherPoint = (2, 0)
    switch anotherPoint {
    case (let x, 0):
        print("on the x-axis with an x value of \(x)")
    case (0, let y):
        print("on the y-axis with a y value of \(y)")
    case let (x, y):
        print("somewhere else at (\(x), \(y))")
    }
    // 输出 "on the x-axis with an x value of 2"
    
    

    Kotlin:

    牛!

    Swift:

    switch 分支的模式还可以使用 where 语句来判断额外的条件。如下:

    let yetAnotherPoint = (1, -1)
    switch yetAnotherPoint {
    case let (x, y) where x == y:
        print("(\(x), \(y)) is on the line x == y")
    case let (x, y) where x == -y:
        print("(\(x), \(y)) is on the line x == -y")
    case let (x, y):
        print("(\(x), \(y)) is just some arbitrary point")
    }
    // 输出 "(1, -1) is on the line x == -y"
    
    

    这时候当且仅当控制表达式匹配一个 case 的模式且 where 子句的表达式为真时,case 中的语句才会被执行.

    Kotlin:

    请收下我的膝盖。。。

    Swift:

    哈哈,接下来我们切磋一下循环语句吧

    Kotlin:

    好,Kotlinfor 循环和 while 循环与 Java 里面的语法差别不大,不过得益于 Kotlin 的析构功能,我们可以在迭代中方便的使用多个参数。

    for ((index, value) in array.withIndex()) {
        println("the element at $index is $value")
    }
    

    Swift:

    我们也有类似的写法。

    for (index, value) in array.enumerated() {
        print("the element at \(index) is \(value)")
    }
    
    

    除了 for-in语句外, 我们也有 whilerepeat-while 来实现循环遍历。

    Kotlin:

    你的 repeat-while 是不是和我们的 do-while 一样?

    Swift:

    是的,一模一样。

    Kotlin:

    Kotlin 提供了灵活的标签功能,在跳转表达式出现歧义的时候,可以支持以标签的方式制定跳转表达式要跳转的位置,如在嵌套循环中。例如:

    loop@ for (i in 1..100) {
        for (j in 1..100) {
            if (……) break@loop
        }
    }
    

    Swift:

    我们也有类似的标签功能。

    var sum = 0
    
    rowLoop: for row in 0..<8 {
      columnLoop: for column in 0..<8 {
        if row == column {
          continue rowLoop
        }
        sum += row * column
      }
    }
    

    Kotlin:

    嗯嗯,看上去就是标签的定义方式不一样,我们要多写一个 @.

    不过我们的标签还可以用在函数中,例如:

    fun foo() {
        ints.forEach lit@ {
            if (it == 0) return@lit
            print(it)
        }
    }
    

    Swift:

    我们不能

    Kotlin:

    甚至我们还可以使用隐式的标签。

    fun foo() {
        ints.forEach {
            if (it == 0) return@forEach
            print(it)
        }
    }
    

    Swift:

    嗯,你们的标签功能比我们强大。

    Kotlin:

    好了,今天我们就到此为止吧,和你交流还是收获颇丰的。

    Swift:

    (^-^)V,青山不改,绿水长流,咱们江湖再见。

    Kotlin:

    后会有期。

    知识点总结

    Kotlin

    条件判断

    在 Kotlin 中用 if 做判断有两种用法,一种是用作传统的条件判断,另一种是做为表达式。

    当用作传统的条件判断的时候,跟 Java 没有什么差异。

    var max: Int
    if (a > b) {
        max = a
    } else {
        max = b
    }
    

    if 用作表达式的时候,可以有值返回,如 val b = if (a > 0) a else 0。这样的用法很像 Java 里的三目运算,所以在 Kotlin 里面就没有再单独提供三目运算了。

    if 作为表达式的时候后面也可以接块代码,在块代码中随后一行的输出会作为该块代码的返回值。

    val max = if (a > b) {
        print("Choose a")
        a
    } else {
        print("Choose b")
        b
    }
    

    需要注意的是,在用作表达式的时候,后面必须提供 else

    when 表达式

    Kotlin 用 when 表达式替代 Java 里面的 switch-case,不过不仅仅是替代,when 表达式提供了更加强大的功能。

    普通的条件匹配
    when (x) {
        1 -> print("x == 1")
        2 -> print("x == 2")
        else -> { // 注意这个块
            print("x is neither 1 nor 2")
        }
    }
    

    when 会顺序比较所有的条件,匹配到合适的以后机会执行条件后面对应的表达式(类似 if也可以是块),当所有的条件都不满足的时候就会执行 else 后面的表达式。所有的when 表达式中都要提供 else,除非 Kotlin 能推断出不会再有其他条件存在。

    当有不同的分支需要同样的处理的话,可以用逗号分隔写在一起。

    when (x) {
        0, 1 -> print("x == 0 or x == 1")
        else -> print("otherwise")
    }
    
    匹配任意表达式

    when 不仅支持常量的条件匹配,还可以支持任意表达式的匹配,所以你可以这样肆无忌惮的使用它来匹配某个数是否在某某范围。

    when (x) {
        in 1..10 -> print("x is in the range")
        in validNumbers -> print("x is valid")
        !in 10..20 -> print("x is outside the range")
        else -> print("none of the above")
    }
    

    或者匹配未知类型的类型。

    fun hasPrefix(x: Any) = when(x) {
        is String -> x.startsWith("prefix")
        else -> false
    }
    
    无参数匹配

    when 可以不提供参数,直接顺序匹配满足条件的表达式后,执行其对应后面的表达式。

    when {
        x.isOdd() -> print("x is odd")
        x.isEven() -> print("x is even")
        else -> print("x is funny")
    }
    

    循环

    Kotlin 的 for 循环和 while 循环和 Java 里面的语法差别不大,不过得益于 Kotlin 的析构功能,我们可以在迭代中方便的使用多个参数。

    for ((index, value) in array.withIndex()) {
        println("the element at $index is $value")
    }
    

    带标签的返回(return)、中断(break)和继续(continue)

    Kotlin 提供了灵活的标签功能,在跳转表达式出现歧义的时候,可以支持以标签的方式制定跳转表达式要跳转的位置,如在嵌套循环中。

    loop@ for (i in 1..100) {
        for (j in 1..100) {
            if (……) break@loop
        }
    }
    

    或者在函数中,

    fun foo() {
        ints.forEach lit@ {
            if (it == 0) return@lit
            print(it)
        }
    }
    

    甚至我们还可以使用隐式的标签。

    fun foo() {
        ints.forEach {
            if (it == 0) return@forEach
            print(it)
        }
    }
    

    Swift

    条件判断

    swift 使用 if 语句或 guard 语句来做条件判断。if 语句与 c语言等其他类型语句没有差别。guard 则是把不符合条件的处理事件前置,提前退出,避免了代码金字塔的出现,使代码看起来更优雅,更易读。

    例如:

    func greet(person: [String: String]) {
        guard let name = person["name"] else {
            return
        }
        
        print("Hello \(name)!")
        
        guard let location = person["location"] else {
            print("I hope the weather is nice near you.")
            return
        }
        
        print("I hope the weather is nice in \(location).")
    }
     
    greet(person: ["name": "John"])
    // Prints "Hello John!"
    // Prints "I hope the weather is nice near you."
    greet(person: ["name": "Jane", "location": "Cupertino"])
    // Prints "Hello Jane!"
    // Prints "I hope the weather is nice in Cupertino."
    
    

    不同于 if 语句,一个 guard 语句必须要有一个 else 从句与之配对。

    Switch 语句

    swiftswitch 语句来进行条件匹配,例如:

    let x = 1
    
    switch x {
    case 1:
        print("x == 1")
    case 2:
        print("x == 2")
    default:
        print("x is neither 1 nor 2")
    }
    
    

    任何类型的值都可以作为控制表达式的值。当有不同的分支需要同样的处理的话,可以将这个几个值组合成一个复合匹配,并且用逗号分开,如下:

    switch x {
    case 0, 1:
        print("x == 0 or x == 1")
    default:
        print("otherwise")
    }
    
    
    Fallthrough

    当匹配到的 case 中的代码执行完毕后,switch 语句会直接退出,而不会继续执行下一个 case ,如果确实想执行下一个 case,需要显式的在当前 case 中使用 fallthrough 语句。例如:

    let integerToDescribe = 5
    var description = "The number \(integerToDescribe) is"
    switch integerToDescribe {
    case 2, 3, 5, 7, 11, 13, 17, 19:
        description += " a prime number, and also"
        fallthrough
    default:
        description += " an integer."
    }
    print(description)
    // 输出 "The number 5 is a prime number, and also an integer."
    
    元组

    可以使用元组在同一个 switch 语句中测试多个值。元组中的元素可以是值,也可以是区间。另外,可以使用下划线(_)来匹配所有可能的值。例如:

    let somePoint = (1, 1)
    switch somePoint {
    case (0, 0):
        print("(0, 0) is at the origin")
    case (_, 0):
        print("(\(somePoint.0), 0) is on the x-axis")
    case (0, _):
        print("(0, \(somePoint.1)) is on the y-axis")
    case (-2...2, -2...2):
        print("(\(somePoint.0), \(somePoint.1)) is inside the box")
    default:
        print("(\(somePoint.0), \(somePoint.1)) is outside of the box")
    }
    // 输出 "(1, 1) is inside the box"
    
    
    值绑定

    不仅如此,case 分支还允许将匹配的值绑定到一个临时的常量或变量,并且在 case 分支体内使用:

    let anotherPoint = (2, 0)
    switch anotherPoint {
    case (let x, 0):
        print("on the x-axis with an x value of \(x)")
    case (0, let y):
        print("on the y-axis with a y value of \(y)")
    case let (x, y):
        print("somewhere else at (\(x), \(y))")
    }
    // 输出 "on the x-axis with an x value of 2"
    
    
    where 子句

    switch 分支的模式可以使用 where 语句来判断额外的条件, 例如:

    let yetAnotherPoint = (1, -1)
    switch yetAnotherPoint {
    case let (x, y) where x == y:
        print("(\(x), \(y)) is on the line x == y")
    case let (x, y) where x == -y:
        print("(\(x), \(y)) is on the line x == -y")
    case let (x, y):
        print("(\(x), \(y)) is just some arbitrary point")
    }
    // 输出 "(1, -1) is on the line x == -y"
    
    

    这时候当且仅当控制表达式匹配一个 case 的模式且 where 子句的表达式为真时,case 中的语句才会被执行.

    循环语句

    Swift 中的循环语句包括:for-in, whilerepeat-while, while 与其他语言的 while 无二, repeat-while 则与 do-while 一致。

    for-in 语句的形式如下:

    for <item> in <collection> {
        <statements>
    }
    
    

    可以使用 for-in 语句来遍历一个序列,例如数组中的元素、数字范围或者字符串中的字符等.

    使用 for-in语句遍历一个 Dictionary 来访问其键值对,如下:

    let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
    for (animalName, legCount) in numberOfLegs {
        print("\(animalName)s have \(legCount) legs")
    }
    
    

    for-in 还可以用来遍历一个数字范围,例如:

    for index in 1...10 {
        print("\(index)")
    }
    
    

    带标签的语句

    swift 中,可以使用标签来标记一个循环语句或 switch 语句。对于一个 switch 语句,可以使用 break 加标签的方式,来结束这个被标记的语句。对于一个循环语句,可以使用 breakcontinue 加标签,来结束或者继续执行这条被标记的语句。

    var sum = 0
    
    rowLoop: for row in 0..<8 {
      columnLoop: for column in 0..<8 {
        if row == column {
          continue rowLoop
        }
        sum += row * column
      }
    }
    

    相关文章

      网友评论

        本文标题:Swift vs. Kotlin 漫谈之控制流

        本文链接:https://www.haomeiwen.com/subject/izgzcxtx.html