让你迷惑的 Kotlin 代码(1)

2021-08-31 15:42:40 浏览数 (1)

今天在 Medium 看到了一个很有趣的小知识,爬上来和大家分享一下。题目是这样的:

代码语言:javascript复制
fun printIt(num: Int) {
    if (num < 0) {
        print("negative")
    } else if (num > 0) {
        print("positive")
    } else {
        print("zero")
    }
}

fun main() {
    printIt(-1)
    print(",")
    printIt(1)
    print(",")
    printIt(0)
}

大家可以猜一下答案。

代码语言:javascript复制
A. negative,positive,zero
B. ,positive,zero
C. negative,,zero
D. negative,positive,

毫无疑问,大家的答案肯定是 A

那么?这道题的意义何在呢?

......

......

......

好吧,没错,答案就是 A 。可能没有写过代码的同学都能知道是 A 。容我把题目稍作改动。

代码语言:javascript复制
fun printIt(num: Int) {
    if (num < 0) {
        "negative"
    } else if (num > 0) {
        "positive"
    } else {
        "zero"
    }.let { print(it) }
}

fun main() {
    printIt(-1)
    print(",")
    printIt(1)
    print(",")
    printIt(0)
}

仔细对比两道题目,模拟一下你的内心独白。

这题肯定不会选 A 了,除非博主是傻 X ! 不选 A,这题答案是什么呢? 博主是真傻 X,这题肯定还是选 A !

不妨打开 IDE 执行以下,控制台冷冷清清的输出了 ,positive,zero

negative 凭空消失了?

对于 Kotlin 代码,凡事不决,首先反编译。看看 Java 代码长什么样子。

代码语言:javascript复制
   public static final void printIt(int num) {
      if (num >= 0) {
         String var1 = num > 0 ? "positive" : "zero";
         System.out.print(var1);
      }

   }

没错,negative 的确凭空消失了。

再回过头对比一下两次的代码,如下图。

左边的代码在条件判断分支中执行打印语句,符合我们想象中的执行逻辑,这没有问题。

右边的代码在 let 代码块中执行打印语句,虽然不符合我们想象中的执行逻辑,但是它仍然打印了 ,positive,zero 。说明这个 let 成功作用在了一个 String 对象上,间接说明了 Kotlin 的 if/else 是有返回值的。

那么,为什么第一个 if 的返回值被忽略了呢?因为作用域函数 let 。先来看另一段代码:

代码语言:javascript复制
fun printIt(num: Int) {
    (if (num < 0) {
        "negative"
    } else if (num > 0) {
        "positive"
    } else {
        "zero"
    }).let { print(it) }
}

这段代码如你所想,工作正常。因为使用 () 显示指定了执行 let 函数的对象。

到这里,你应该也明白上面是怎么回事了。let 的执行上下文遵循了 就近原则 , 下图中的两段代码是等价的。

原文中还有几道有意思的题目,大家可以进去看看,地址:https://blog.kotlin-academy.com/puzzlers-on-kotlin-academy-week-1-84f42437ee94 。

0 人点赞