Это связано с тем, что use
является встроенной функцией, что означает, что тело лямбда-выражения будет встроено в функцию сайта вызова, а фактический тип переменной myVar
зависит от ее контекста.
ЕСЛИ myVar
используется в лямбде для чтения, это тип MyType
или его супертип. Например:
// v--- the actual type here is MyType
var myVar: MyType = TODO()
autoClosable.use {
myVar.todo()
}
ЕСЛИ myVar
используется в лямбда-выражении для записи, фактический тип — 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
использоваться в теле лямбда другой неинлайновой функции в будущем. или kotlin хотят сохранить семантическую согласованность для всех функций.
person
holi-java
schedule
21.07.2017