Scope-функции ("функции-области") в Kotlin — это стандартные функции (let, also, run, apply, with), которые позволяют управлять контекстом исполнения блока кода для объекта. Они отличаются:
it или через this.| Функция | this/it | Возвращает | Для чего? |
|---|---|---|---|
| let | it | результат | цепочка операций, работа с nullable, map |
| also | it | объект | сайд-эффекты, логгирование, дебаг |
| run | this | результат | вычисления, инициализация с возвратом |
| apply | this | объект | конфигурация объекта, билдеры |
| with | this | результат | работа с внешними API, объект "снаружи" |
Примеры:
let: удобно, если объект nullable:val str: String? = "Text" str?.let { println(it.length) }
apply: настройка объекта:val paint = Paint().apply { color = Color.RED strokeWidth = 2f }
run: выполнение на объекте, возвращаем результат:val length = "abcde".run { length }
with: для работы с внешним объектом:val sb = StringBuilder() with(sb) { append("Hello, ") append("world!") toString() }
also: для сайд-эффектов (например, логов):val list = mutableListOf(1, 2, 3) list.also { println("Before: $it") }.add(4)
it, менять свойства объекта не очень удобно.this / it), полезно для билдеров.with — это обычная функция, не extension.В чём отличие между let и also?
Ответ:
it внутри блока,let возвращает результат лямбды, часто используется для цепочек трансформации,also возвращает исходный объект, используется для побочных эффектов (l og, дебаг), чтобы не вмешиваться в цепочку преобразования.Пример:
val result = listOf(1).also { println(it) }.map { it * 2 } // результат — List<Int>
История
Новичок использовал let для настройки объекта, считая, что так можно изменить его состояние "в цепочке". В результате по завершении блока конфигурации получал не объект, а результат лямбды (например, ничего), из-за чего нарушался цепочка построения DSL.
История
При написании кода по работе с nullable-объектами, использовали run вместо let, не заметив разницы в возвращаемом значении. В итоге результат выражения отличался от ожидаемого, появлялись null там, где не должно было быть — логика приложения ломалась.
История
В большом билдере случайно использовали with для внутренних объектов, рассчитывая на паттерн extension. Поскольку with — это не extension-функция, цепочка из нескольких with-блоков работала некорректно, внутренние вызовы путались и выходили за границы актуального объекта. Пришлось полностью переписывать иерархию создания объектов.