我有以下代码片段:
val foo: String? = null
foo.run { println("foo") }
我这里有一个可以为空的变量foo
,实际上设置为null
,然后是非安全.run()
来电。
当我运行代码段时,尽管在foo
上调用run
方法,但仍会打印null
。这是为什么?为什么没有NullPointerException
?为什么编译器允许对可选值进行非安全调用?
如果我通过println(foo)
,我会在控制台中获得一个很好的多汁null
,所以我认为foo
实际上是null
是安全的。
答案 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") }