Урок 6. Функции, параметры и значения по умолчанию
Функция — именованный кусок программы, который можно вызывать много раз. Функции избавляют от повторения одинакового кода и делят большую программу на понятные части. main и println — тоже функции: первую пишете вы, вторая уже есть в Kotlin. В этом уроке — как писать свои.
Первая функция
fun square(x: Int): Int {
return x * x
}
fun main() {
println(square(5))
println(square(12))
}25
144Из чего состоит объявление:
fun— начало функции,square— её имя;(x: Int)— параметр: имя и тип через двоеточие. Тип параметра писать обязательно;: Intпосле скобок — тип результата, который функция возвращает;return x * x— вернуть значение и закончить функцию.
При вызове square(5) значение 5 — аргумент — попадает в параметр x, функция считает 5 * 5 и возвращает
- Функции можно объявлять до
mainили после — порядок в файле не важен.
Функция в одну строку
Если всё тело функции — одно выражение, фигурные скобки и return можно убрать и написать =:
fun square(x: Int) = x * x
fun larger(a: Int, b: Int) = if (a > b) a else b
fun main() {
println(square(7))
println(larger(3, 9))
}49
9Тип результата здесь компилятор выводит сам. Параметров может быть сколько угодно — через запятую.
Функции без результата
Функция может ничего не возвращать, а только что-то делать — например, выводить:
fun greetAll(names: List<String>) {
for (name in names) {
println("Hello, $name!")
}
}
fun main() {
greetAll(listOf("Anna", "Oleg"))
}Hello, Anna!
Hello, Oleg!Тип результата у такой функции — Unit («ничего полезного»), его не пишут. В Java и C на этом месте стоит void. return без значения в такой функции досрочно её заканчивает.
Параметры по умолчанию и именованные аргументы
Параметру можно дать значение по умолчанию — тогда при вызове его можно не указывать:
fun greet(name: String = "guest", times: Int = 1) {
repeat(times) {
println("Hello, $name!")
}
}
fun main() {
greet()
greet("Anna")
greet("Oleg", 2)
greet(times = 2)
}Hello, guest!
Hello, Anna!
Hello, Oleg!
Hello, Oleg!
Hello, guest!
Hello, guest!greet()— оба параметра берутся по умолчанию;greet("Anna")— задано имя,timesпо умолчанию;greet(times = 2)— именованный аргумент: пропустить первый параметр и задать второй по имени.
Именованные аргументы делают вызов понятнее, когда параметров много: createUser(name = "Anna", age = 20, admin = false) читается лучше, чем createUser("Anna", 20, false).
Функция, которая отвечает «да» или «нет»
Функции с результатом Boolean удобно называть с is: isPrime, isEmpty. Внутри может быть несколько return — функция заканчивается на первом сработавшем:
fun isPrime(n: Int): Boolean {
if (n < 2) return false
var d = 2
while (d * d <= n) {
if (n % d == 0) return false
d++
}
return true
}
fun main() {
for (n in 1..20) {
if (isPrime(n)) {
println(n)
}
}
}2
3
5
7
11
13
17
19Делители проверяются только до корня из n (d * d <= n): если у числа есть делитель больше корня, то есть и меньше.
Параметры менять нельзя
Параметры функции ведут себя как val: присвоить им новое значение нельзя, x = x + 1 внутри функции не соберётся. Нужна изменяемая копия — объявите переменную: var current = x.
Переменные, объявленные внутри функции, видны только в ней. В разных функциях могут быть переменные с одинаковыми именами — они не мешают друг другу.
Рекурсия
Функция может вызывать сама себя — это рекурсия. Факториал: 5! = 5 · 4 · 3 · 2 · 1:
fun factorial(n: Int): Long = if (n <= 1) 1 else n * factorial(n - 1)
fun main() {
println(factorial(5))
println(factorial(20))
}120
2432902008176640000У рекурсии обязательно должен быть случай, где она останавливается (n <= 1). Без него функция вызывает себя бесконечно, и программа падает с ошибкой StackOverflowError. Результат здесь — Long: уже 13! не помещается в Int.
Переменное число аргументов
vararg позволяет передать сколько угодно значений одного типа — внутри функции они видны как массив:
fun sumAll(vararg numbers: Int): Int {
var s = 0
for (n in numbers) {
s += n
}
return s
}
fun main() {
println(sumAll(1, 2, 3))
println(sumAll(10, 20))
println(sumAll())
}6
30
0Лямбды
Функцию можно записать и без имени, прямо как значение, — это лямбда. Она пишется в фигурных скобках: параметры, стрелка -> и тело:
fun main() {
val double = { x: Int -> x * 2 }
println(double(4))
val numbers = listOf(1, 2, 3)
println(numbers.map { it * 10 })
}8
[10, 20, 30]Если у лямбды один параметр, его можно не называть — он доступен как it. Лямбды постоянно встречаются при работе со списками: map { it * 10 } — «каждый элемент умножить на 10». Подробнее — в уроке Коллекции.
Коротко
fun имя(параметр: Тип): ТипРезультата { ... return ... }.- Одно выражение — короче:
fun square(x: Int) = x * x. - Без результата — тип
Unit, его не пишут. - Значения по умолчанию:
fun greet(name: String = "guest"); именованный вызов:greet(name = "Anna"). - Параметры менять нельзя — они как
val. - Лямбда — функция-значение:
{ x: Int -> x * 2 }, с одним параметром —it.