Почему компилятор Kotlin требует явного инициализатора свойства var?
Я не могу понять следующую часть документации Kotlin:
The initializer, getter and setter are optional. Property type is optional
if it can be inferred from the initializer or from the base class member being overridden.
Examples:
var allByDefault: Int? // error: explicit initializer required, default
getter and setter implied
Единственное объяснение, почему компилятор требует здесь явного инициализатора (по крайней мере, единственное объяснение, которое я могу придумать) заключается в том, что у Kotlin нет значений свойств по умолчанию. Это правильно? Если да, то почему? Другими словами: в чем разница между свойствами Kotlin и полями Java (которые имеют значения по умолчанию), что не позволяет нам иметь значения свойств по умолчанию?
Ответы
Ответ 1
Это просто: в значениях по умолчанию Java 0
(ноль) и null
. Но в Kotlin большинство значений не являются нулевыми, поэтому вы не можете их инициализировать с помощью null
. Для примитивных значений может существовать стратегия инициализации по умолчанию с нулями, но она не была выполнена, чтобы быть последовательной. Но в примитивных массивах значение по умолчанию равно нулю.
Если вам действительно нужна эта семантика инициализации, взгляните на свойства lateinit
: https://kotlinlang.org/docs/reference/properties.html#late-initialized-properties.
Этот механизм в принципе позволяет инициализировать поле с помощью null
, но затем освобождает вас от нулевых утверждений.
Сложение
На самом деле Котлин очень умный умный об инициализации. Например, это работает:
val x: Int
if(something)
x = 1
else
x = 2
println(x)
Здесь kotlinc может предположить, что x
инициализируется до его использования, поэтому код в порядке
Ответ 2
Котлин ничего не делает неявным образом. Он не преобразует числовые типы без вашей конкретной инструкции и не устанавливает значение по умолчанию или инициализацию без его явного. Это выбор дизайна для устранения распространенных ошибок, которые были обнаружены в типичных Java-программах. Неясно компилятору, если вы забыли инициализировать его или если вы предназначались для значения по умолчанию, которое будет использоваться. Поскольку это не ясно, это плохо. И поэтому, вероятно, это приводит к ошибкам.
Выбор дизайна Kotlin помогает устранить ошибки из-за кода, в котором компилятор не может определить, есть ли ошибка. Это философский и последовательный язык.
Kotlin требует инициализации перед использованием. Для членов, которые означают, что к тому времени, когда конструкторы и инициализаторы завершены, он должен иметь значение. Модификатор lateinit
на var
позволяет это игнорировать во время компиляции, хотя во время выполнения проверка выполняется при доступе к переменной. Для локальных переменных любая ветвь кода должна инициализировать значение перед доступом. Например:
fun stateFromAbbreviation(abbreviation: String?): String {
val state: String
if (abbreviation == null) {
state = DEFAULT_STATE
}
else {
state = stateMap.get(abbreviation) ?: throw IllegalStateException("Invalid state abbreviation $abbreviation")
}
return state
}
Здесь локальная переменная может быть инициализирована в выражении if
, предполагая, что все ветки инициализируют значение. Но на самом деле этот код был бы более идиоматичным, используя if
в качестве выражения, например:
fun stateFromAbbreviation(abbreviation: String?): String {
return if (abbreviation == null) {
DEFAULT_STATE
}
else {
stateMap.get(abbreviation) ?: throw IllegalStateException("Invalid state abbreviation $abbreviation")
}
}