Как и все остальные, я изучаю Kotlin. И я пытаюсь сделать это правильно. Поэтому я объявляю переменную в моем классе:
private lateinit var mLastMarker: Marker
MLastMarker отслеживает последний раз, когда я использовал маркер, поэтому я могу удалить его при создании нового маркера (google maps api). Поэтому при добавлении нового маркера я сначала хочу удалить старый:
// remove last marker (if it exists)
mLastMarker?.remove()
// add this marker to the map
mLastMarker = mMap.addMarker(markerOptions)
Что имеет смысл для меня. Я думаю, что я буду выполнять функцию remove()
если mLastMarker
не является нулевым. Он будет установлен сразу после и, таким образом, будет вызывать remove()
каждый раз после первого (когда есть что удалить).
Но я получаю предупреждение. ?.
выделено предупреждающим сообщением в заголовке. Что дает? Чего мне не хватает в нулевой безопасности Котлина?
Всего 2 ответа
При использовании lateinit
null
значение никогда не будет сохранено в вашей собственности. Обратите внимание, что его тип, Marker
, не является обнуляемым Marker?
тип - на самом деле вы не можете создать свойство, которое может быть как lateinit
, так и lateinit
.
Используя lateinit
, вы говорите, что компилятору не нужно проверять обнуляемость в любой момент и что вы всегда ожидаете, что значение уже будет в свойстве, прежде чем вы его когда-либо прочитаете. Если вы прочитаете его перед установкой, вы не получите null
, вместо этого он выдаст исключение. Вы также никогда не сможете вернуть его в неинициализированное состояние, если вы дали ему значение, потому что оно не примет значение null
в качестве нового значения.
В общем, lateinit
хорош, если вы хотите инициализировать что-то один раз, прежде чем начать его использовать, но по какой-то причине не можете инициализировать его при создании свойства (например, во время создания класса).
Если вам иногда приходится проверять, есть ли у вас значение в данный момент, лучше использовать свойство, допускающее значение NULL (хотя вы можете технически проверить, инициализирована ли переменная lateinit
, но это не очень красиво).
private lateinit var mLastMarker: Marker
Объявляет экземпляр типа Marker
.
private lateinit var mLastMarker: Marker?
Объявляет экземпляр типа nullable Marker
.
Значит, в твоем случае нулевая безопасность ?
проверка избыточна, потому что mLastMarker
не может быть нулевым.
Так:
mLastMarker?.remove()
Возможно:
mLastMarker.remove()
Путаница, вероятно, вызвана тем, что вы используете lateinit
, поэтому я предполагаю, что вы поняли, что значение может быть null
. Это немного странно, потому что в том, что касается компилятора, значение не может быть null
, но, если вы не назначите значение lateinit
где-то до того, как получите к нему доступ, оно фактически будет «по существу» null
(не совсем, но концептуально) и доступ к нему приведет к UninitializedPropertyAccessException
Иногда вам действительно нужно свойство lateinit
, но чаще всего вы можете его избежать. Я бы посоветовал взглянуть на ваш код и посмотреть, действительно ли вам нужен lateinit
или вы можете создать его lateinit
или, в качестве альтернативы, именно там, где это требуется.