在龙目岛扩展方法中,obj.method()
是SomeUtil.method(obj)
的语法糖。它允许obj
为空。
Kotlin 扩展方法是静态解析的,所以我假设它是相同的语法糖。但是当我写的时候
fun Any.stringOrNull() = this?.toString()
我收到有关非空接收器上不必要的安全呼叫的警告。这是否意味着我不能像龙目岛那样在空对象上调用扩展函数?
如果将可为 null 的对象定义为可空类型的扩展,则可以在可空对象上调用它:
fun Any?.stringOrNull() = ...
否则,与任何其他方法一样,您必须使用安全调用运算符。
可以在可为空的接收器类型上创建扩展。在您的示例中,它必须是Any?
的,而不是不允许 null 的Any
,请参阅文档:
可为空接收器
请注意,可以使用可为空的接收器类型定义扩展。这样的扩展可以在对象变量上调用,即使它的值是
null
,并且可以检查主体内部的this == null
。这就是允许您在不检查null
的情况下在 Kotlin 中调用toString()
的原因:检查发生在扩展函数内部。fun Any?.toString(): String { if (this == null) return "null" // after the null check, 'this' is autocast to a non-null type, so the toString() below // resolves to the member function of the Any class return toString() }
请注意:
fun Any?.toString(): String
以下行为:
var obj: Any? = null
obj?.toString() // is actually null
obj.toString() // returns "null" string
只是花了 15 非常令人沮丧的分钟才意识到这一点......
val string: string? = "Hello World!"print(string.length(
编译错误:无法直接访问可为 null 类型的属性。打印(字符串?长度(将打印字符串的长度,如果字符串为 null,则为"null"。
?.
可为空接收器的安全呼叫运算符##
如果左侧的值为 null,则安全调用运算符返回 null,否则继续计算右侧的表达式,因此为了在可为 null 的接收器上调用任何函数,您需要在 Any 之后使用安全调用运算符。(使用任何?然后你可以在函数体内检查这个(这里this object points to receiver
(的空值。这就是允许您在 Kotlin 中调用 toString(( 而不检查 null 的原因:检查发生在扩展函数内部。
fun Any?.toString(): String { if (this == null) return "null" // after the null check, 'this' is autocast to a non-null type, so the toString() below // resolves to the member function of the Any class return toString() }