Я (личное мнение) думаю, что это хорошая идея - использовать простые, регулярные проверки на ноль, где это возможно, хотя метод ?.let
был указан на главной странице документации Kotlin Idioms (которая открыт для участия сообщества) - так что, в основном, это будет зависеть от ваших личных предпочтений, из которых более читабельный.
Более интересный вопрос заключается в том, в чем заключаются различия и когда вы можете использовать каждое из них: основное отличие заключается в том, что let
сохраняет значение переменной, как это было, когда начался вызов let
для нее, и любое последующее использование it
в блоке let
будет ссылаться на это же значение. Если вы используете простую нулевую проверку с if
, значение вашей переменной может измениться во время выполнения тела блока if
.
Так, например, это не скомпилируется, потому что x
может быть доступно нескольким потокам, и оно может быть ненулевым, когда вы сначала читаете его значение для проверки на ноль, но оно может стать нулевым к тому времени Вы читаете его снова для параметра println
- это будет небезопасно:
class Foo {
var x: Int? = null
fun useX() {
if (x != null) {
println(x + 10) // (...) 'x' is a mutable property that could have been changed by this time
}
}
}
Однако let
будет работать в той же ситуации, потому что он будет использовать все начальное значение x
, которое имело все время его выполнения, даже если свойство x
в классе тем временем будет переназначено:
class Foo {
var x: Int? = null
fun useX() {
x?.let {
println(it + 10)
}
}
}
Вы можете подумать о приведенном выше операторе ?.let
, который в основном выполняет это, создавая временную копию вашей переменной:
fun useX() {
val _x = x
if (_x != null) {
println(_x + 10)
}
}
Работа с этой копией безопасна, потому что даже если свойство x
изменит свое значение, эта копия _x
останется нулевой для всей этой функции, или она будет ненулевой и безопасной для использования.