为什么不安全的.run()调用在Kotlin中的空值上工作正常?

时间:2017-08-02 20:43:52

标签: kotlin kotlin-null-safety

我有以下代码片段:

val foo: String? = null
foo.run { println("foo") }

我这里有一个可以为空的变量foo,实际上设置为null,然后是非安全.run()来电。

当我运行代码段时,尽管在foo上调用run方法,但仍会打印null。这是为什么?为什么没有NullPointerException?为什么编译器允许对可选值进行非安全调用?

如果我通过println(foo),我会在控制台中获得一个很好的多汁null,所以我认为foo实际上是null是安全的。

2 个答案:

答案 0 :(得分:4)

要添加@ holi-java所说的内容,您的代码根本就没有任何不安全感。无论println("foo")是否为空,foo都完全有效。如果您尝试了类似

的内容
foo.run { subString(1) }

这将是不安全的,你会发现它甚至不会在没有某种空检查的情况下进行编译:

foo.run { this?.subString(1) }
// or
foo?.run { subString(1) }

答案 1 :(得分:2)

这是因为顶级函数run接受任何Any& Any?。所以Kotlin在运行时没有检查Null Receiver的扩展函数。

//                 v--- accept anything
public inline fun <T, R> T.run(block: T.() -> R): R = block()

确实,如果run可以可以,则内联函数receiver由Kotlin生成而没有任何断言,因此更像是为Java代码生成的noinline函数如下:

public static Object run(Object receiver, Function1<Object, Object> block){
   //v--- the parameters checking is taken away if the reciever can be nullable
  //Intrinsics.checkParameterIsNotNull(receiver, "receiver");

  Intrinsics.checkParameterIsNotNull(block, "block");
  // ^--- checking the `block` parameter since it can't be null 
}

IF 您希望以安全的方式调用它,您可以改为使用safe-call运算符?.,例如:

val foo: String? = null

// v--- short-circuited if the foo is null
foo?.run { println("foo") }