【问题标题】:kotlin: extension methods and null receiverkotlin:扩展方法和空接收器
【发布时间】:2018-01-24 17:02:36
【问题描述】:
在 lombok 扩展方法中,obj.method() 是SomeUtil.method(obj) 的语法糖。它允许obj 为空。
Kotlin 扩展方法是静态解析的,所以我认为它是相同的语法糖。但是当我写的时候
fun Any.stringOrNull() = this?.toString()
我收到关于非空接收器上不必要的安全调用的警告。这是否意味着我不能像 Lombok 那样对空对象调用扩展函数?
【问题讨论】:
标签:
kotlin
kotlin-extension
【解决方案1】:
如果将它定义为可空类型的扩展,则可以在可空对象上调用它:
fun Any?.stringOrNull() = ...
否则,与任何其他方法一样,您必须使用safe call operator。
【解决方案2】:
您可以在可为空的接收器类型上创建扩展。在您的示例中,它必须是 Any? 而不是 Any 不允许 null,请参阅 docs:
可空接收器
请注意,可以使用可为空的接收器类型来定义扩展。即使对象变量的值为null,也可以在对象变量上调用此类扩展,并且可以检查主体内的this == null。这就是允许您在 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()
}
【解决方案3】:
小心,因为:
fun Any?.toString(): String
以下行为:
var obj: Any? = null
obj?.toString() // is actually null
obj.toString() // returns "null" string
在意识到这一点之前花了 15 分钟非常令人沮丧...
【解决方案4】:
val 字符串:字符串? =“你好世界!”
打印(字符串。长度)
// 编译错误:不能直接访问可为空类型的属性。
打印(字符串?。长度)
// 将打印字符串的长度,如果字符串为空,则打印“null”。
?. 可空接收器的安全调用运算符##
如果左边的值为 null,则安全调用运算符返回 null,否则继续计算右边的表达式,因此为了调用可空接收器上的任何函数,您需要在 Any 之后使用安全调用运算符。(使用任何?)
然后你可以在函数体内检查 this(这里是 this object points to receiver) 的 null 值。这就是允许你在 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()
}