首页 > 解决方案 > 当对象为空时,何时使用 let/run/apply/with/also?

问题描述

所以我读了如果对象为空,如何运行代码?但我还不知道何时使用 let,run... 等。我想要这样的东西:

myVar?.xxx{
  // do something if is not null
} ?: xxx{
  // do something is myVar is null
}

最佳做法是什么?谢谢 :)

标签: androidkotlinnull

解决方案


最佳实践是不要将作用域函数与 Elvis 运算符链接来处理 null/not null,因为它的可读性较差并且容易出错。仅仅因为您 可以做某事并不意味着您应该做某事!内联作用域函数提供了很大的功能,因此也有很大的误用和可读性较差的代码的可能性。

例如,第一个作用域函数的返回值(如果它是letrun)可能为 null 并导致第二个作用域函数也运行并返回超出您预期的内容。

您链接的问题是旧的,并且从有很多新的 Kotlin 用户开始,因为 Android 采用它作为推荐语言。许多新用户对内联作用域函数感到兴奋,并且可能过于渴望尽可能多地使用它们,而不是仅仅在它们是最合适的工具的地方使用它们。请注意,在显示如何完成的投票最多的答案中,建议仍然使用 if/else,因为这样更具可读性。

如果myVar是局部变量(或val没有自定义 getter 的本地定义属性),您应该这样做:

if (myVar != null) {
    // myVar will be smart cast to non-null inside this if block.
    //TODO
else {
    //TODO
}

如果myVar是一个var属性,你可以这样做:

myVar.let { 
    if (it != null) {
        // it will be smart cast to non-null inside this if block.
        //TODO
    else {
        //TODO
    }
}

// OR

val myLocalVar = myVar
if (myLocalVar != null) {
    // myLocalVar will be smart cast to non-null inside this if block.
    //TODO
else {
    //TODO
}

为了解决您的具体问题,如果您真的决心这样做(而且您不应该这样做!),那么使用myVar.also { } ?: run { }. 该also函数不返回结果,而是返回调用它的内容,因此不存在意外触发两个作用域函数的风险。apply也可以,但是通常如果您要运行整个代码块,则不希望将其用作接收器。那可读性会降低。而对于第二个作用域函数,run最有意义,因为它不会从外部作用域改变接收器,因此它在这里对可读性造成的摩擦最小。


推荐阅读