Kotlin – 安全呼叫运营商的链接。 不必要的话务员

以下面使用安全调用操作符(?。)的示例:

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。 但是为什么我们需要在sampleC上安全的调用操作符。 如果我删除该运算符,它不会编译。

基于我对运算符的理解,如果sampleB为空,则该行将返回null。 如果sampleB不为null,我们可以确定sampleC不是null,根据它的types。 但为什么Kotlin强制安全调用operatorC?

 A().sampleB?.sampleC?.sampleInt 

解析为

 ((A().sampleB)?.sampleC)?.sampleInt 

types是

 A(): A A().sampleB: B? (A().sampleB)?.sampleC: C? ((A().sampleB)?.sampleC)?.sampleInt: Int? 

因为sampleC之前的types是B??. 是必须的。

首先,安全呼叫运营商?. 不会打破安全通话链。 当你写A().sampleB?.sampleC?.sampleInt ,如果A().sampleB为null,则链不会停在?.sampleC但是它会执行null?.sampleCA().sampleB?.sampleC将是C? 但不是C因为它取决于整个expression式而不是属性的types。 那是为什么?. 如果前面的expression式是可以为空的,则是需要的。

如果sampleB是链中唯一可为空的expression式,则可以考虑使用.run

 val intInC: Int? = A().sampleB?.run { sampleC.sampleInt } 

我猜测你不相信,因为,正如你所说,如果它达到了链接点.sampleC被称为是因为sampleB不是空的,如果它是空的,它不会达到这一点。

这里的要点是,你正在考虑实施,从这个意义上说,你可能是对的。 但是,你需要从语义上解释它:尽管为了优化的原因,比方说,当它find一个null之前,它不需要走到最后,即使在那里,整条线也需要有连贯的含义是空的。 而为了这个事实,你需要? 符号。