今天在 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
。先来看另一段代码:
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 。