Перейти к содержанию
Educora
Средний20 мин5 / 14

Функции и лямбды

Пиши собственные функции: значения по умолчанию и именованные аргументы, функции из одного выражения, функции-расширения, лямбды и функции высшего порядка.

Проверь себя
В этом уроке ты узнаешь
  • Определять функцию с параметрами и типом возвращаемого значения
  • Использовать значения по умолчанию, именованные аргументы и функции из одного выражения
  • Добавлять функции-расширения к существующим типам
  • Писать лямбду и передавать её в функцию высшего порядка

Представь, что в десяти местах программы ты собираешь один и тот же текст приветствия. Когда текст понадобится изменить, придётся исправлять десять мест! Функция позволяет написать код один раз, дать ему имя и вызывать сколько угодно раз. Ты уже работал с функциями: main, println и repeat — это функции. Теперь ты создашь свои.

Объявление функции

Функция начинается со слова fun, затем идут её имя и параметры в скобках. В Kotlin у каждого параметра обязательно указывается тип: name: String. После скобок через двоеточие пишут тип возвращаемого значения, а результат возвращают с помощью return. Функция, которая ничего не возвращает, имеет тип Unit, и его можно не писать.

Kotlin
fun greet(name: String, greeting: String = "Hello"): String {
    return "$greeting, $name!"
}

fun printLine(length: Int = 10) {
    println("-".repeat(length))
}

fun main() {
    println(greet("Aysel"))
    println(greet("Murad", "Salam"))
    println(greet(greeting = "Hi", name = "Leyla"))
    printLine()
    printLine(5)
}
Ожидаемый результат
Hello, Aysel!
Salam, Murad!
Hi, Leyla!
----------
-----
  • greeting: String = "Hello" — значение по умолчанию: если при вызове аргумент не передан, используется "Hello".
  • greet(greeting = "Hi", name = "Leyla") — именованные аргументы: если указать имена параметров, порядок не важен, а код читается понятнее.
  • printLine ничего не возвращает — её тип Unit, она просто выводит текст на экран.

Функции из одного выражения

Если вся работа функции — вычислить одно выражение, фигурные скобки и return можно убрать и записать выражение после знака =. Тип результата компилятор выведет сам. Поскольку if и when — выражения, их тоже можно использовать в такой функции.

Kotlin
fun square(x: Int) = x * x
fun isEven(n: Int) = n % 2 == 0
fun rectangleArea(width: Double, height: Double) = width * height
fun result(score: Int) = if (score >= 50) "passed" else "failed"

fun main() {
    println(square(7))
    println(isEven(10))
    println(rectangleArea(4.0, 2.5))
    println(result(73))
}
Ожидаемый результат
49
true
10.0
passed

Функции-расширения

В Kotlin можно «добавить» новую функцию к существующему типу, даже к стандартному, например String или Int. Для этого перед именем функции пишут тип и точку: fun String.shout(). Внутри функции this — это само значение. Потом такую функцию вызывают как обычный метод: "salam".shout().

Kotlin
fun String.shout() = uppercase() + "!"
fun Int.isEven() = this % 2 == 0
fun Double.toManat() = "$this AZN"

fun main() {
    println("salam".shout())
    println(8.isEven())
    println(12.5.toManat())
}
Ожидаемый результат
SALAM!
true
12.5 AZN

Лямбды

Лямбда — это короткая функция без имени, записанная в фигурных скобках: { x: Int -> x * 2 }. Слева от стрелки параметры, справа — тело; значение последнего выражения и есть результат лямбды. Лямбду можно сохранить в переменной, а её тип записывается так: (Int) -> Int — «принимает Int, возвращает Int». Если у лямбды один параметр, его можно не объявлять и обращаться к нему по имени it.

Kotlin
fun main() {
    val double = { x: Int -> x * 2 }
    val add: (Int, Int) -> Int = { a, b -> a + b }
    val greet: (String) -> String = { "Hello, $it!" }
    println(double(21))
    println(add(3, 4))
    println(greet("Elvin"))
}
Ожидаемый результат
42
7
Hello, Elvin!

Функции высшего порядка

Функция, которая принимает другую функцию как параметр (или возвращает её), называется функцией высшего порядка. Ниже applyTwice применяет переданную ей операцию дважды. Если лямбда — последний аргумент, её можно вынести за скобки. А готовую функцию можно передать через ::, например ::multiply.

Kotlin
fun applyTwice(x: Int, f: (Int) -> Int): Int = f(f(x))

fun calculate(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
    return operation(a, b)
}

fun multiply(a: Int, b: Int) = a * b

fun main() {
    println(applyTwice(3) { it + 10 })
    println(applyTwice(5) { it * it })
    println(calculate(8, 2) { a, b -> a - b })
    println(calculate(8, 2, ::multiply))
}
Ожидаемый результат
23
625
6
16
applyTwice(5) { it * it }: сначала 5 · 5 = 25, затем 25 · 25 = 625.

Стандартная библиотека полна функций, принимающих лямбды. Даже repeat(3) { ... } из прошлого урока — функция высшего порядка! У строк count считает символы, подходящие под условие, а filter оставляет только их:

Kotlin
fun main() {
    val word = "Programming"
    println(word.count { it == 'm' })
    println(word.filter { it !in "aeiou" })
    println(word.any { it.isDigit() })
    repeat(2) { i -> println("Attempt ${i + 1}") }
}
Ожидаемый результат
2
Prgrmmng
false
Attempt 1
Attempt 2
repeat передаёт в лямбду номер шага, начиная с 0.

Главное

  • Функция записывается как fun имя(параметр: Тип): ТипРезультата { ... }; функция без результата имеет тип Unit.
  • Значения по умолчанию делают аргументы необязательными, а именованные аргументы снимают зависимость от порядка.
  • Функция из одного выражения: fun square(x: Int) = x * x.
  • Функция-расширение добавляет новый метод к существующему типу: fun String.shout().
  • Лямбда — функция без имени: { a, b -> a + b }; единственный параметр называется it.
  • Функция высшего порядка принимает другую функцию как параметр; последнюю лямбду можно вынести за скобки.

Проверь себя

Вопросов: 10. Каждый правильный ответ приносит XP.

1 / 10
Дано fun area(w: Int, h: Int = 2) = w * h. Чему равно area(5)?