Примеры использования run, let, apply, also и with в Kotlin: когда что применять?
Основное правило: смотрим на контекст и возвращаемое значение
Все эти функции (run, let, apply, also, with) — это scope functions. Они создают временную область видимости для объекта. Главное различие — как они передают объект внутрь блока (через this или it) и что возвращают (сам объект или результат лямбды).
Краткая шпаргалка
- apply — контекст:
this, возвращает: сам объект. Используйте для настройки свойств объекта. - also — контекст:
it, возвращает: сам объект. Используйте для побочных действий (логирование, проверки). - let — контекст:
it, возвращает: результат лямбды. Используйте для преобразований и проверок на null. - run — контекст:
this, возвращает: результат лямбды. Используйте для вычислений на основе объекта. - with — не расширение, контекст:
this, возвращает: результат лямбды. Используйте для группировки вызовов методов объекта.
Пример 1: Настройка объекта — apply
Когда нужно создать объект и сразу инициализировать его поля. apply возвращает сам объект, поэтому можно присвоить результат переменной.
val user = User().apply {
name = "Иван"
age = 25
email = "ivan@mail.ru"
}
// user уже заполнен, можно использовать
Пример 2: Побочное действие — also
Когда нужно что-то сделать с объектом, но не менять его суть. Например, залогировать или проверить.
val user = User("Иван", 25, "ivan@mail.ru")
.also { println("Создан пользователь: ${it.name}") }
.also { if (it.age < 18) throw Exception("Малолетний") }
Пример 3: Преобразование с null-check — let
Самый частый use-case — работа с nullable объектами. let выполняется только если объект не null.
val userName: String? = getUserName()
userName?.let {
println("Имя пользователя: $it, длина: ${it.length}")
}
Также let хорош для цепочек преобразований:
val emailLength = User("Иван", 25, "ivan@mail.ru")
.let { it.email }
.let { it.length } // вернёт Int = 12
Пример 4: Вычисления с контекстом объекта — run
Когда нужно выполнить несколько операций с объектом и вернуть какой-то результат. Объект доступен как this.
val isAdult = user.run {
age >= 18 && name.isNotBlank() // вернёт Boolean
}
Пример 5: Группировка вызовов — with
Не является функцией-расширением, но удобна, когда у вас уже есть объект и нужно много раз обратиться к его методам.
with(user) {
println("Имя: $name, возраст: $age")
sendEmail(email)
}
Сводная таблица для быстрого выбора
| Функция | Контекст | Возвращает | Когда использовать |
|---|---|---|---|
| apply | this | объект | Настройка объекта |
| also | it | объект | Побочные эффекты |
| let | it | результат | Преобразования, null-check |
| run | this | результат | Вычисления с объектом |
| with | this | результат | Группировка вызовов |
Совет: начните с apply и let — они покрывают 80% случаев. Остальные добавляйте постепенно, когда почувствуете необходимость.
Дополнение: цепочки вызовов и читаемость
Коллеги уже отлично описали базовые различия. Хочу добавить про то, как эти функции помогают писать читаемые цепочки. Частая ошибка новичков — пытаться использовать одну функцию везде. На самом деле, комбинируя их, вы получаете самодокументируемый код.
Пример: создаём пользователя, проверяем возраст, логируем и отправляем приветствие.
val result = User()
.apply {
name = "Анна"
age = 30
}
.also { println("Создан: ${it.name}") }
.let { user ->
if (user.age >= 18) "Взрослый: ${user.name}"
else "Ребёнок: ${user.name}"
}
.also { println("Результат проверки: $it") }
// result — строка "Взрослый: Анна"
Обратите внимание: apply настраивает объект, also логирует, let преобразует, и снова also для побочного действия. Каждая функция чётко говорит о своём назначении. Если бы мы написали всё через run, код был бы менее очевидным.
Ещё один лайфхак: если вы видите, что внутри блока let или run вы не используете результат, а просто вызываете методы — скорее всего, нужно apply или also. И наоборот, если внутри apply вы что-то вычисляете и пытаетесь вернуть — переходите на run.
Главное — не бойтесь экспериментировать. Со временем вы научитесь выбирать функцию интуитивно, просто потому что она лучше смотрится в конкретном контексте.
Ответов пока нет.
Войдите чтобы оставить ответ