Kotlin - 安全调用操作符的链接。不必要的接线员电话
Kotlin - chaining of safe call operator. unnecessary operator calls
以下面使用安全调用运算符 (?.) 的示例为例:
class Sample {
class A(
val sampleB: B? = B()
)
class B(
val sampleC: C = C()
)
class C(
val sampleInt: Int = 1
)
fun test() {
val intInC: Int? = A().sampleB?.sampleC?.sampleInt
}
}
我知道我们需要 sampleB 上的安全调用操作符。但是为什么我们需要安全调用运算符 on sampleC。
如果我删除该运算符,它不会编译。
根据我对运算符的理解,如果 sampleB 为空,则 returns 行为空。如果 sampleB 不为空,我们可以根据其类型确定 sampleC 不为空。但为什么 Kotlin 在 sampleC 上强制使用安全调用运算符?
A().sampleB?.sampleC?.sampleInt
解析为
((A().sampleB)?.sampleC)?.sampleInt
类型是
A(): A
A().sampleB: B?
(A().sampleB)?.sampleC: C?
((A().sampleB)?.sampleC)?.sampleInt: Int?
因为 sampleC
之前的类型是 B?
,所以需要 ?.
。
首先,安全调用操作符?.
不会打断安全调用链。当你写 A().sampleB?.sampleC?.sampleInt
时,如果 A().sampleB
为空,链将不会在 ?.sampleC
处停止,而是会执行 null?.sampleC
。 A().sampleB?.sampleC
的类型将是 C?
而不是 C
因为它取决于整个表达式而不是 属性 的类型。这就是为什么如果前面的表达式可以为空,则需要 ?.
。
如果 sampleB
是链中唯一可为空的表达式,您可以考虑使用 .run
:
val intInC: Int? = A().sampleB?.run { sampleC.sampleInt }
我猜你不相信,因为正如你所说,如果它到达链中调用 .sampleC
的点,那是因为 sampleB
不为空,如果它为空它不会达到这一点。
这里的重点是您是从实施的角度考虑的,从这个意义上说,您可能是对的。但是您需要从语义上解释它:即使出于优化的原因,假设它在之前找到空值时不需要转到行尾,但整行仍然需要具有连贯的含义,即使在那里是空值。为此,您需要 ?
符号。
以下面使用安全调用运算符 (?.) 的示例为例:
class Sample {
class A(
val sampleB: B? = B()
)
class B(
val sampleC: C = C()
)
class C(
val sampleInt: Int = 1
)
fun test() {
val intInC: Int? = A().sampleB?.sampleC?.sampleInt
}
}
我知道我们需要 sampleB 上的安全调用操作符。但是为什么我们需要安全调用运算符 on sampleC。 如果我删除该运算符,它不会编译。
根据我对运算符的理解,如果 sampleB 为空,则 returns 行为空。如果 sampleB 不为空,我们可以根据其类型确定 sampleC 不为空。但为什么 Kotlin 在 sampleC 上强制使用安全调用运算符?
A().sampleB?.sampleC?.sampleInt
解析为
((A().sampleB)?.sampleC)?.sampleInt
类型是
A(): A
A().sampleB: B?
(A().sampleB)?.sampleC: C?
((A().sampleB)?.sampleC)?.sampleInt: Int?
因为 sampleC
之前的类型是 B?
,所以需要 ?.
。
首先,安全调用操作符?.
不会打断安全调用链。当你写 A().sampleB?.sampleC?.sampleInt
时,如果 A().sampleB
为空,链将不会在 ?.sampleC
处停止,而是会执行 null?.sampleC
。 A().sampleB?.sampleC
的类型将是 C?
而不是 C
因为它取决于整个表达式而不是 属性 的类型。这就是为什么如果前面的表达式可以为空,则需要 ?.
。
如果 sampleB
是链中唯一可为空的表达式,您可以考虑使用 .run
:
val intInC: Int? = A().sampleB?.run { sampleC.sampleInt }
我猜你不相信,因为正如你所说,如果它到达链中调用 .sampleC
的点,那是因为 sampleB
不为空,如果它为空它不会达到这一点。
这里的重点是您是从实施的角度考虑的,从这个意义上说,您可能是对的。但是您需要从语义上解释它:即使出于优化的原因,假设它在之前找到空值时不需要转到行尾,但整行仍然需要具有连贯的含义,即使在那里是空值。为此,您需要 ?
符号。