Прямые ссылки на публичные уроки для быстрого старта и стабильной индексации lesson-страниц.
В Kotlin есть анонимные функции и лямбды — оба понятия иногда называют анонимными функциями, и далее станет ясно почему.
Анонимные функции — это классические функции без имени. Они объявляются с помощью ключевого слова fun, умеют принимать и возвращать параметры. На практике такая функция может использоваться прямо в момент объявления — например, как обработчик нажатия кнопки в Android-приложении. О коллбэках подробнее поговорим в рамках Android.
Создадим анонимную функцию, которая возвращает количество оставшихся дней до Нового года. Сначала создадим экземпляр объекта даты с помощью абстрактного класса Calendar и его метода getInstance(). Затем объявим функцию без имени — в развёрнутой форме с телом и в краткой:
fun main() { val calendar: Calendar = Calendar.getInstance() fun(): Int { return 365 - calendar[Calendar.DAY_OF_YEAR] } }
Краткая форма:
fun() = 365 - calendar[Calendar.DAY_OF_YEAR]
Анонимную функцию можно сохранять в переменную, передавать в другую функцию как параметр или возвращать из метода. Тип переменной записывается так: слева от стрелки — типы принимаемых параметров, справа — возвращаемый тип.
val getDaysToEndYear: () -> Int = fun() = 365 - calendar[Calendar.DAY_OF_YEAR]
Вызвать функцию, сохранённую в переменную, можно через invoke() или через круглые скобки:
fun main() { val calendar: Calendar = Calendar.getInstance() val getDaysToEndYear: () -> Int = fun() = 365 - calendar[Calendar.DAY_OF_YEAR] println(getDaysToEndYear.invoke()) }
Создадим ещё одну анонимную функцию — она будет принимать количество дней и печатать результат конвертации в миллисекунды. Тип (Int) -> Unit означает: принимает Int, ничего не возвращает.
val convertEndDaysToMills: (Int) -> Unit = fun(endDays: Int) = println(1000 * 60 * 60 * 24 * endDays) convertEndDaysToMills(getDaysToEndYear())
Лямбда-выражение — объект, содержащий блок кода. По сути это функция, и её можно называть анонимной функцией.
Ключевые тезисы:
fun не используется.return — результат автоматически возвращается из последнего выражения в теле.Создадим переменную для хранения лямбды, инициализируем её и вызовем:
val printStringWithLambda: () -> Unit printStringWithLambda = { println("print string with lambda") } printStringWithLambda()
Лямбду можно объявить и вызвать в одну строку:
// короткая запись { println("print string with lambda") }()
Важный нюанс. Если перед лямбдой стоит вызов другой функции, Kotlin может интерпретировать открывающую фигурную скобку как дополнительный параметр предыдущего вызова. Это типичный «пазлер»:
printStringWithLambda() { println("print string with lambda") }()
Чтобы разделить вызовы, достаточно поставить точку с запятой после printStringWithLambda().
Добавим входной целочисленный параметр и используем его в теле. В развёрнутой и краткой формах:
val printStringWithLambda: (Int) -> Unit printStringWithLambda = { println("print string with lambda $it") } printStringWithLambda(42); // короткая запись { it: Int -> println("print string with lambda $it") }(442)
Что здесь важно:
it — неявное имя параметра, которое появляется, когда лямбда принимает один параметр и компилятор способен определить его тип. Это имя можно переименовать для читаемости.it: Int ->) обязательна, стрелка всегда присутствует.Теперь сделаем лямбду возвращающей значение. Для возврата из лямбды return не нужен — возвращается последнее выражение в теле:
val printStringWithLambda: (Int) -> String printStringWithLambda = { it: Int -> "print string with lambda $it" } printStringWithLambda(42); // короткая запись { it: Int -> "print string with lambda $it" }.invoke(442)
Итоговый пример, объединяющий оба подхода. Лямбда конвертирует и печатает количество дней; анонимная функция вычисляет дни до Нового года:
val printStringWithLambda: (Int) -> String printStringWithLambda = { it: Int -> "print string with lambda $it" } println(printStringWithLambda(42)); // короткая запись println({ it: Int -> "print string with lambda $it" }.invoke(442)) // конвертация дней в миллисекунды val convertLambda = { endDays: Int -> println("Convert from lambda: ${1000 * 60 * 60 * 24 * endDays}") } convertLambda(getDaysToEndYear())