Эквивалент Swift 'if let' в Kotlin: как безопасно распаковать Optional?
Основной способ: использование let с ?: (элвис-оператор)
В Kotlin нет прямого синтаксического аналога Swift if let, но комбинация функций let и элвис-оператора ?: решает ту же задачу. Вот как это выглядит:
val optionalValue: String? = "Hello"
// Аналог if let с обработкой else
optionalValue?.let { unwrappedValue ->
println("Значение есть: $unwrappedValue")
} ?: run {
println("Значение отсутствует")
}
Разберём по частям:
optionalValue?.let { ... }— безопасный вызовlet. ЕслиoptionalValueнеnull, то внутри лямбды переменнаяit(или именованнаяunwrappedValue) уже гарантированно неnull.?: run { ... }— элвис-оператор. Еслиletвернулnull(что происходит, когда исходное значениеnull), то выполняется блокrun.
Вариант с присвоением результата
Если нужно не только выполнить действие, но и получить значение (например, для дальнейшего использования), можно записать так:
val result = optionalValue?.let { "Обработано: $it" } ?: "Значение null"
println(result) // Выведет: "Обработано: Hello"
Использование when для более сложных сценариев
Если у вас несколько nullable-переменных или нужна более сложная логика, подойдёт конструкция when:
val name: String? = "Alice"
val age: Int? = 30
when {
name != null && age != null -> {
println("Имя: $name, возраст: $age")
}
else -> {
println("Недостаточно данных")
}
}
Smart cast (умное приведение)
Kotlin поддерживает smart cast: после проверки на null в условии if компилятор автоматически считает переменную ненулевой внутри блока. Это работает, если переменная val (неизменяемая):
if (optionalValue != null) {
// Здесь optionalValue автоматически приведён к String (не String?)
println("Длина: ${optionalValue.length}")
} else {
println("null")
}
Для var (изменяемых) переменных
Если переменная объявлена через var, smart cast не сработает, так как значение может измениться между проверкой и использованием. В таком случае используйте let или временную val:
var mutableValue: String? = "Test"
// Вариант 1: let
mutableValue?.let { value ->
println(value)
}
// Вариант 2: временная val
val temp = mutableValue
if (temp != null) {
println(temp)
}
Итоговое сравнение со Swift
- Swift:
if let x = y { ... } else { ... } - Kotlin:
y?.let { x -> ... } ?: run { ... }
Разница в синтаксисе, но логика та же: безопасная распаковка с обработкой обоих случаев. Рекомендую привыкнуть к let + ?: — это идиоматичный Kotlin.
Альтернатива: функция takeIf и also
Если вам нужно не просто распаковать значение, но и выполнить с ним несколько действий, можно комбинировать takeIf с also или apply. Пример:
val optionalValue: String? = "Hello"
optionalValue?.takeIf { it.isNotEmpty() }?.also { value ->
println("Непустое значение: $value")
} ?: println("Значение null или пустое")
Здесь takeIf проверяет дополнительное условие (например, что строка не пустая), и только если условие истинно, выполняется блок also. Если значение null или не прошло проверку, срабатывает else-ветка через ?:.
Расширение для имитации Swift-стиля
Можно написать свою функцию-расширение, чтобы синтаксис был ближе к Swift:
inline fun <T> T?.ifLet(action: (T) -> Unit, elseAction: () -> Unit = {}) {
if (this != null) action(this) else elseAction()
}
// Использование:
optionalValue.ifLet(
action = { println("Значение: $it") },
elseAction = { println("null") }
)
Этот подход даёт читаемый синтаксис, похожий на if let, но добавляет небольшой overhead. Для большинства случаев лучше использовать встроенные let и ?:, так как они являются стандартными и понятными для других Kotlin-разработчиков.