注册

Kotlin ?: 语法糖的 一个坑

问题还原


先定义一个函数


/**
* @param s 字符串
* @return 参数的 长度如果不为1 返回null
*/
fun testStr(s: String): String? {
return if (s.length == 1) {
"length:1"
} else {
null
}
}

然后定义一个类 里面有个函数调用了上面的方法


class Test {
fun testLet() {
testStr("1")?.let {
println("inner let-1")
testStr("11")?.let {
println("inner let-2")
} ?: println("inner else")

} ?: println("outer else")
}
}

在main函数里面跑一下


fun main() {

val t = Test()
t.testLet()
}

看下运行结果:


image.png


到这里还是好理解的, 但是我如果稍微改一下我们的代码


class Test {
fun testLet() {
testStr("1")?.let {
println("inner let-1")
testStr("11")?.let {
println("inner let-2")
}
} ?: println("outer else")
}
}

这个时候 你认为程序应该打印什么?


我觉得多数人可能会认为 程序只会打印一行
inner let-1


然而你运行一下你就会发现:


image.png


他竟然还多打印了 outer else


这个行为我估计很多kotlin开发者就理解不了了, 因为按照javaer 的习惯, if 和 else 总会配对出现
我们上面的代码, 内部的判断逻辑 没有写else 那就不应该有任何行为啊, 为什么 内部的else 逻辑没写的时候
自动给我走了外部的else逻辑?


我们反编译看一下


image.png


这个反编译的代码是符合 程序运行结果的,虽然 他肯定不符合 多数kotlin开发者的意愿,


我们再把代码修改回去,让我们内部的inner case 也有一个else的逻辑


class Test {
fun testLet() {
testStr("1")?.let {
println("inner let-1")
testStr("11")?.let {
println("inner let-2")
} ?: println("inner else")
} ?: println("outer else")
}
}

再反编译看一下代码:


image.png


这个代码就很符合我们写代码时候的意愿了


到这里我们就可以下一个结论


对于 ?: 这样的语法糖来说 ,如果内部 使用了?. 的写法 而没有写?: 的逻辑,则当内部的代码真的走到else的逻辑时,外部的?: 会默认执行


另外一个有趣的问题


下面的let 为什么会报错?


image.png


这里就有点奇怪了,这个let的写法为什么会报错? 但是run的写法 却是ok的?
而且这个let的写法 在我们第一个小节的代码中也没报错啊? 这到底是咋回事


看下这2个方法的定义


image.png


image.png


最关键就在于 这个let 需要有一个receiver, 而如果这个let 刚才在main函数中的写法就不对了


因为main函数 显然不属于任何一个对象,也不属于任何一个类,let在这个执行环境下 找不到自己的receiver 自然就会编译报错了


但是对于run 来说,这个函数的定义没有receiver的概念,所以可以运行


作者:vivo高启强
链接:https://juejin.cn/post/7229606662289457211
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册