Kotlin let {} не поддерживает Smart Cast

Только что изучил Nullable тип Kotlin и let{} функцию, которая заменяет if (xx != null) {} операцию.

Но меня смущает одна вещь: мы все знаем и я думаю, что Complier должен знать, что, когда мы используем let{}, переменная / объект, который вызывает эту функцию, возможно, имеет значение null, однако компилятор по-прежнему требует мне добавить безопасного оператора вызова? после имени переменной вместо использования Smart Cast, как в if (xx != null) {}. Почему?

Мой фрагмент кода:

fun main() {
    var number1: Int? = null

    //val number2 = number1.let { it + 1 } ?: 10    //doesn't work, not quite "smart"
    val number2 = number1?.let { it + 1 } ?: 10     //works, must have "?"

    println(number1)
    println(number2)
}

person Sam Chen    schedule 15.11.2020    source источник
comment
let не делает то, что вы думаете. Это «функция области действия», то есть функция, используемая для выполнения блока кода в другой области действия. Это не имеет ничего общего с null. Оператор Kotlin nullsafe выполняет вызовы методов для ссылки при условии, что эта ссылка не равна нулю. Итак, комбинируя два x?.let{ ...}, вы выполняете блок кода в том случае, если цель не равна нулю.   -  person Boris the Spider    schedule 15.11.2020
comment
Отвечает ли это на ваш вопрос? Какова цель ключевого слова let в Kotlin   -  person Boris the Spider    schedule 15.11.2020
comment
Я согласен с @BoristheSpider, это не имеет ничего общего с Null, это всего лишь механизм обзора, такой как run или apply   -  person a_local_nobody    schedule 15.11.2020
comment
На самом деле @a_local_nobody - let, run, apply и also - четыре функции области видимости Kotlin.   -  person Boris the Spider    schedule 15.11.2020
comment
let{} ничего не меняет в переменной / объекте, в котором вы его используете, но если вы используете ?let{}, то вы имеете в виду ненулевой экземпляр переменной / объекта, поэтому, просто используя let{}, вы просто используете та же переменная / объект, который все еще может быть нулевым   -  person a_local_nobody    schedule 15.11.2020
comment
@BoristheSpider добавляет еще два: use и with :)   -  person Animesh Sahu    schedule 15.11.2020
comment
Отвечает ли это на ваш вопрос? Понимание необходимости Kotlin let   -  person Animesh Sahu    schedule 15.11.2020


Ответы (1)


У вас уже есть ответы в комментариях, но просто чтобы объяснить суть ? ...

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

nullableObject?.someProperty?.someFunction()

который оценивает nullableObject, и если он не равен нулю, он оценивает следующий бит, в противном случае все выражение оценивается как null. Если какая-либо часть цепочки оценивается как null, все выражение возвращает null.

Таким образом, у него есть этот эффект короткого замыкания, и вы можете использовать оператор elvis if null для создания значения по умолчанию, если вы не можете оценить всю цепочку до ненулевого результата:

nullableObject?.nullableProperty?.someFunction() ?: defaultAction()

и как только вы введете нулевую проверку в цепочку, вам нужно будет добавлять ее для каждого последующего вызова - она ​​в основном распространяет либо результат предыдущего бита, либо null, который он разрешил, поэтому на каждом шаге есть нулевая проверка


Блок let - это просто функция области видимости - вы используете его для значения, поэтому вы можете запустить некоторый код, используя это значение в качестве параметра или получателя (переменная или this в основном). Он также имеет побочный эффект создания новой временной локальной переменной, содержащей это значение, поэтому, если исходное значение равно var, не имеет значения, изменится ли это значение, потому что ваш let код больше не ссылается на эту переменную.

Так что это полезно для выполнения нулевых проверок один раз, не беспокоясь о том, что базовое значение может стать нулевым, пока вы что-то с ним делаете:

nullableVar?.let { it.definitelyIsNotNull() }

и компилятор распознает это и умно преобразует его в ненулевой тип. Проверка if (nullableVar != null) не может гарантировать, что nullableVar не будет нулевым к моменту выполнения следующей строки.

person cactustictacs    schedule 15.11.2020
comment
Хорошо, позвольте мне сделать вывод. Во-первых, оператор безопасного вызова ? предназначен только для типа Nullable. Во-вторых, при использовании безопасного вызова ? для переменной Nullable следующие операции (функции / свойство), вызываемые этой переменной, будут выполняться ТОЛЬКО ЕСЛИ ОН НЕ ПУСТО (избегайте NullPointerException), и это поведение / механизм не обеспечивается функцией let{}. Я прав? - person Sam Chen; 16.11.2020
comment
И я думаю, что последняя часть, о которой вы упомянули, касается безопасности потоков, что является преимуществом использования let{}. Я узнал об этом из этой статьи: android.jlelse .eu / - person Sam Chen; 16.11.2020
comment
Да, часть, касающаяся изменения переменной, может быть другим потоком, изменяющим ее, или потенциально сопрограммой в том же потоке ... в основном каждый раз, когда есть возможность для изменения переменной, и подрывать какой-то вывод, который вы сделали ранее (например, что это не нуль, или что это is особый тип) вы получите предупреждение об этом. Если он может с уверенностью сказать, что вывод не изменится, тогда он обычно будет умным актером для вас. Таким образом, использование функций области видимости дает вам временную переменную (например, вам нужно обезопасить себя), которая гарантированно останется неизменной! - person cactustictacs; 16.11.2020
comment
? перед вызовом делает это только в том случае, если объект, на котором вы его вызываете, разрешается к ненулевому значению. Это мешает вам выполнять вызовы вещей, которые имеют значение null (поэтому у вас нет метода для вызова), но вы также можете использовать его в качестве базовой проверки на null - и это рекомендуемый стиль Kotlin для того, если переменная не равна нулю. эта штука с кодом типа it, а оператор elvis действует как else. Вы все еще можете вызвать let для нулевого значения - вы можете сделать null.let { ... }, это просто означает, что переменная, переданная в функцию, равна null, и вам решать, как безопасно обрабатывать это внутри блока кода. - person cactustictacs; 16.11.2020