这是因为use 是一个内联函数,这意味着 lambda 主体将内联到调用点函数,而变量 myVar 的实际类型取决于其上下文.
IF myVar 在 lambda 中用于读取,类型为 MyType 或其超类型。例如:
// v--- the actual type here is MyType
var myVar: MyType = TODO()
autoClosable.use {
myVar.todo()
}
IF myVar 在 lambda 中用于写入,实际类型是 ObjectRef。为什么?这是因为 Java 不允许您将变量更改出令人讨厌的类范围。事实上,myVar 是实际上是最终的。例如:
// v--- the actual type here is an ObjectRef type.
var myVar: MyType
autoClosable.use {
myVar = autoClosable.foo()
}
所以当编译器检查println(myVar) 时,它不能确定ObjectRef 的元素是否被初始化。然后引发编译器错误。
如果抓到什么,代码也编译不出来,例如:
// v--- the actual type here is an ObjectRef type.
var myVar: MyType
try {
autoClosable.use {
myVar = it.foo()
}
} catch(e: Throwable) {
myVar = MyType()
}
// v--- Error: Variable 'myVar' must be initialized
println(myVar)
但是当myVar 的实际类型是MyType 时,它可以正常工作。例如:
var myVar: MyType
try {
TODO()
} catch(e: Throwable) {
myVar = MyType()
}
println(myVar) // works fine
为什么 kotlin 没有优化内联函数直接使用MyType 编写?
我唯一想的是,编译器不知道myVar 将来是否会在另一个内联函数的 lambda 主体中使用。或者 kotlin 想要保持所有函数的语义一致。