Kotlin "let{}" 不提供智能转换

Kotlin "let{}" Doesn't Provide Smart Cast

刚刚学习了 Kotlin Nullable 类型和 let{} 函数,它取代了 if (xx != null) {} 操作。

但是让我感到困惑的一件事是,我们都知道并且我认为编译器应该知道当我们使用let{}时,variable/object谁在调用这个函数可能是空的,但是编译器仍然要求我添加安全调用运算符“?”在变量名之后,而不是像在 if (xx != null) {} 中那样提供 Smart Cast。为什么?

我的一段代码:

fun main() {
    var number1: Int? = null

    //val number2 = number1.let { it + 1 } ?: 10    //doesn't work, not quite "smart"
    val number2 = number1?.let { it + 1 } ?: 10     //works, must have "?"

    println(number1)
    println(number2)
}

您已经在评论中得到了答案,但只是为了解释 ? 事情...

Kotlin 允许您通过在调用前添加 ? 来对可为空的变量和属性进行空安全调用。你也可以通过做

来链接它
nullableObject?.someProperty?.someFunction()

计算 nullableObject,而 如果 为非空,则计算下一位,否则整个表达式计算为 null。如果链的任何部分评估为 null,则整个表达式 returns null.

所以它有这种短路效果,如果你不能将整个链评估为非空结果,你可以使用 elvis 的“if null”运算符来创建一个默认值:

nullableObject?.nullableProperty?.someFunction() ?: defaultAction()

一旦你在链中引入空检查,你必须在之后的每次调用中添加它——它基本上传播前一位的结果,或者它解析到的 null,所以每一步都有空检查


let 块只是一个作用域函数 - 你可以在一个值上使用它,所以你可以 运行 一些代码使用该值作为参数或接收器(变量或 this 基本上)。它还具有创建一个新的临时局部变量来保存该值的副作用,因此如果原始变量是 var 则该值是否更改并不重要,因为您的 let 代码没有引用到那个变量了。

因此,它对进行一次空值检查很有用,而不必担心在使用它时基础值可能变为空值:

nullableVar?.let { it.definitelyIsNotNull() }

编译器会识别并智能地将其转换为非空类型。 if (nullableVar != null) 检查不能保证下一行执行时 nullableVar 不会为空。