Kotlin Предупреждение: ненужный безопасный вызов на ненулевом приемнике типа Marker

Как и все остальные, я изучаю 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 или, в качестве альтернативы, именно там, где это требуется.


Есть идеи?

10000