Kotlin:扩展方法和空接收器



在龙目岛扩展方法中,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()
}