Проблема
Как уже упоминал Энзоки в комментариях, другой поток мог изменить поле после проверки на ноль.Компилятор не может этого знать, поэтому вы должны сказать это.
class A(var field: Thing?) {
fun getField(): Thing {
if (field == null) {
field = Thing()
}
// another thread could have assigned null to field
return field!! // tell the compiler: I am sure that did not happen
}
}
Solution (Eager)
В вашем конкретном случае это было бы хорошоИдея использовать параметр f
(вы могли бы также назвать его «полем», но я избегал этого для ясности) в конструкторе (без val
/ var
) и впоследствии назначить его свойству field
, которомуВы назначаете либо f
, либо новый экземпляр Thing
.
Это можно выразить очень кратко с помощью оператора Элвиса :?
, который принимает левую сторону, если не ноль, и правую часть выражения в противном случае.Итак, в конце поле будет иметь тип Thing
.
class A(f: Thing?) {
val field = f ?: Thing() // inferred type Thing
}
Solution (Lazy)
Так как оно было упомянуто gidds , если вам нужно лениво инициализировать поле, вы можете сделать это, используя делегированные свойства :
class A(f: Thing?) {
val field by lazy {
f ?: Thing() // inferred type Thing
}
}
Сайт вызова не изменяется:
val a = A(null) // field won't be initialized after this line...
a.field // ... but after this