Почему ?. неизбежно при вызове метода, хотя экземпляр не обнуляется?

#android #kotlin #nullable

#Android #котлин #обнуляемый

Вопрос:

Я должен следовать объявлению переменной:

 var baseItemList: MutableList<BaseDataItem>? = null
 

при написании строки:

 baseDataItemsList?.get(position).getObjectTypeNum()
 

Я получаю сообщение об ошибке, в котором говорится, что:

Только безопасные (?.) или ненулевые утвержденные (!!.) Вызовы разрешены для обнуляемого получателя типа BaseDataItem?

но метод get не возвращает BaseDataItem? , только BaseDataItem, поскольку BaseDataItem внутри скобок не имеет вопросительного знака. Может ли кто-нибудь объяснить мне эту ошибку и почему я должен добавить этот вопросительный знак?

Комментарии:

1.Ваши два фрагмента кода не совпадают. Один ссылается на baseItemList , а другой ссылается на baseDataItemsList . Но, предполагая, что это действительно одно и то же, baseDataItemsList?.get() может быть null , потому что, хотя список содержит только не- null значения, baseDataItemsList сам по себе может быть null .

2. @CommonsWare может быть, я чего-то не понимаю, но как может baseDataItemsList?.get() быть null, если он проходит ?. проверку? Не могли бы вы, пожалуйста, объяснить

3. @Rey, ты ответил на мой вопрос 🙂

4. ?. это не «проверка». Он возвращается null , если приемник (левая сторона) есть null . Итак, если baseDataItemsList есть null , baseDataItemsList?.anyFunctionYouWantToCall() будет вычисляться null .

5. baseDataItemsList?.get(...) возвращает null, если baseDataItemsList равно null

Ответ №1:

Глядя на этот код:

 baseDataItemsList?.get(position)?.getObjectTypeNum()
 

Вызов ?.get(position) возвращает позицию, если baseDataItemsList она не равна нулю, но в противном случае возвращает значение null . Таким образом, даже несмотря baseDataItemsList.get() на то, что возвращает BaseDataItem значение, не равное нулю (возможно вызвать только в том случае, если baseDataItemsList оно не равно нулю), безопасный с нулевым baseDataItemsList?.get() значением вызов возвращает BaseDataItem? значение, равное нулю , где условие null указывает, что baseDataItemsList оно равно null . Поэтому вы должны использовать ?.getObjectTypeNum() для учета этого.

Примечание: на мой взгляд, объединение var с изменяемой коллекцией часто является запахом кода, потому что вы делаете что-то изменяемым двумя разными способами, что делает его более подверженным ошибкам в работе.

Комментарии:

1. извините, но я все еще не могу понять. Если проверить, есть ли baseDataItemsList? «передано», почему результат метода get должен быть также с? . если есть какой-либо опасный объект null? Разве цепочка (во время выполнения) не останавливается, когда первая часть безопасных вызовов возвращает значение null? Я думал, что метод get даже не будет запущен. Я сделал ссылку var и из MutableType, так как в большинстве случаев я буду добавлять / удалять из списка, но есть ситуация, когда я не хочу восстанавливать весь список другим списком, на который у меня есть ссылка

2. Это не проверка на прохождение / сбой. ?. означает, что если не null, верните результат вызова this , иначе верните null .

3. @Tenfour04, не могли бы вы сказать мне, работает ли as по-другому и не участвует ли в цепочке безопасных вызовов? в следующем коде: (держатель как ViewHolder)?. leagueNameTextView.text , если holder не является ViewHolder , это означает, что значение null возвращается для всех выражений слева от свойства text , тогда попытка запустить null.text кажется проблемой, но компилятор не заставляет меня ставить знак вопроса перед свойством text . Не могли бы вы объяснить мне, почему?

4. holder as ViewHolder приводит его к ненулевому ViewHolder . Это явное, небезопасное приведение, и если holder имеет значение null или не является ViewHolder , вы получите исключение NullPointerException или ClassCastException соответственно во время выполнения. Если вы хотите выполнить безопасное приведение к обнуляемому ViewHolder, вы бы использовали holder as? ViewHolder .

5. @Tenfour04 еще раз спасибо 🙂 Я не заметил, что если забыл вопросительный знак при использовании as?.. Спасибо!!! но проблема с as? что я должен делать это каждый раз, когда использую holder ? Приведение не сохраняется? Или, может быть, вставить as? в if statmement : if(держатель как? ViewHolder != null)

Ответ №2:

Используйте функции области видимости Котлина, например let , область видимости, чтобы избежать этого предупреждения:

 baseDataItemsList?.let { baseDataItemList ->
  baseDataItemList.get(position).getObjectTypeNum()
}
 

Таким образом, вы утверждаете, что baseDataItemList не может находиться null внутри области let видимости. Если вы хотите узнать больше об этой теме, загляните в документацию

Комментарии:

1. Является ли это более «правильным» способом сделать это, а не так, как я это написал (с другим безопасным вызовом)?