如何避免“?.let”嵌套“ null check”?

时间:2019-06-26 02:38:05

标签: kotlin null

让Kotlin帮助我避免一些if(null?)doSomething。

但是我有问题。

A是对象的字段,而B是对象A的字段。它们可以是空包。

他们在这样的代码中。

class Obj {
   var a : A?
}

class A {
   var b : B?
}

我知道我可以通过双重租赁来做到这一点:

A?.let { 
   it.B.let {
      // a must nonnull
   }
}
A?.B?.let {
  // how to use A ,without null check again? 
}

5 个答案:

答案 0 :(得分:3)

有扩展功能可以实现所需的功能,您可以在此线程https://discuss.kotlinlang.org/t/kotlin-null-check-for-multiple-nullable-vars/1946中找到它们

但是,老实说,最好在这里使用基本的if检查,如果变量是可变的,则可以先将其分配给val

val _a = a
val _b = b
if (_a != null && _b != null) {

}

编辑:如果您仍然想使用let,在这种情况下,您可以创建一个配对并使用takeIf

(a to b)
    .takeIf { (a, b) ->
        a != null && b != null
    }
    ?.let { (a, b) ->

    }

但是,编译器不会将值智能广播为非空值,因此您仍然必须对它们执行非空(!!)断言。

答案 1 :(得分:2)

默认情况下,Kotlin避免使用null的值,而对于Null Safety,它提供了:

1)安全呼叫接线员(?。)
2)非空断言(!!)
3)猫王Opeartor(?:)
4)使用let(?.let {...})

进行安全呼叫
  • 安全呼叫操作员(?。):在执行任何操作之前检查属性是否不为空。

  • 非空断言(!!):明确告诉编译器该属性不为null,如果为null,请抛出null指针异常(NPE)

  • Elvis Opeartor(?:):就像Java中的三元运算符。如果property不为null,则返回left表达式,否则返回right。

  • 带有let(?.let {...})的安全调用:仅当属性不为null时,才会执行let块

  

一个示例(属性内含非空值):

    fun main() {
      val name: String? = "Sumit"
      println("Safe Call operator: ${name?.length}")
      name?.let {
          println("Safe Call wih let operator: ${name.length}")
      }
      val length = name?.length ?: 0
      println("Elvis operator : $length")
      println("Not Null Assertion Operator : ${name!!.length}")
   }  

输出(属性内部具有非空值)
    安全呼叫接线员:5
    让操作员安全呼叫:5
    猫王运算符:5
    非空声明运算符:5

输出(属性中带有空值)(值名称:字符串?= null)

Safe Call operator: null
Elvis operator : 0
Exception in thread "main" kotlin.KotlinNullPointerException
  at HelloKt.main(Hello.kt:14)
  at HelloKt.main(Hello.kt)

在这里,不执行带有let的安全呼叫!!非空断言运算符会引发空指针异常。

您的问题可以使用非null断言运算符:

A?.B?.let {   
    // If A and B are not null then only this block will be executed.  
      A.someMethod()  
      B.someMethod()
}

答案 2 :(得分:1)

您可以像使用精灵操作员?:

Swift 后卫一样实现它
fun doSomething() {
    val a = A ?: return
    val b = B ?: return
    doSomethingWith(a, b)
}

这里ab是对您所保存数据的不可空引用,在这种情况下,您只需从函数中返回即可。

答案 3 :(得分:0)

另一种选择是写这样的东西

fun <A, B> A?.and(that: B?, block: (A, B) -> Unit) {
    this?.let { a -> that?.let { b -> block(a, b) } }
}

然后像这样使用它

var first: Int?
var second: Int?

first.and(second) { f, s -> someFunction(f,s) }

答案 4 :(得分:0)

您可以将when用作多个变量的or或语句

when(null) {
  a, b -> return  //for your case of nested properties try something like "obj.a, obj?.a?.b"
  else -> doSomethingWhenAAndBAreNotNull()
}
//or do something when a and b are not null here so you don't need to nest