在空对象上调用扩展方法时,会在错误的类型上调用

Jlu*_*uoH 9 extension-methods kotlin

fun main() {
    val set: Set<Int>?
    set = null
    val emptySet: Set<Int> = set.orEmpty()
}
Run Code Online (Sandbox Code Playgroud)

即使将 set 变量显式键入为 Set <Int>,仍无法弄清楚为什么?编译器认为扩展方法set.orEmpty () set - 是一个字符串,因此会崩溃并出现错误:

Kotlin:类型不匹配:推断类型为 String,但预期为 Set

但是当在一行中声明和初始化时,一切都会正确发生:

fun main() {
    val set: Set<Int>? = null
    val emptySet: Set<Int> = set.orEmpty()
}
Run Code Online (Sandbox Code Playgroud)

luk*_*s.j 0

我认为这与编译器不够聪明以至于可以推断出代码集= null有关将只执行一次 \xe2\x80\x93 它可能是零次或多次。

\n

如果您知道它将运行一个,您可以使用名为kotlin.contracts 的功能告诉编译器:

\n
import kotlin.contracts.ExperimentalContracts\nimport kotlin.contracts.InvocationKind\nimport kotlin.contracts.contract\n\n@ExperimentalContracts\nfun main() {\n  val set: Set<Int>?\n  once { set = null }\n  val emptySet: Set<Int> = set.orEmpty()\n}\n\n@ExperimentalContracts\nfun once(lambda: () -> Unit) {\n  contract { callsInPlace(lambda, InvocationKind.EXACTLY_ONCE) }\n  lambda()\n}\n
Run Code Online (Sandbox Code Playgroud)\n

请参阅https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.contracts/

\n

  • 它能推导出什么或改变多少次并不重要。变量的类型明确是一个 Set,无论它是否已初始化,因此它不应该调用 `String?.orEmpty()`。 (4认同)