Функции в Kotlin #
Васильев Андрей Михайлович, 2024
Версии презентации
Определение фукнции #
В Kotlin функции объявляются с помощью ключевого слова fun
fun double(x: Int): Int {
return 2 * x
}
- Функция обычно начинается со строчной буквы
- Слова в названии выделяютс с помощью camelCase, 2-е и последующие слова пишутся с заглавной буквы
Использование функций #
При вызове функции используется традиционный подход:
val result = double(2)
Для вызова вложенной функции используется знак точки
Stream().read() //создаёт экземпляр класса Stream и вызывает read()
Параметры #
Параметры функции записываются аналогично системе обозначений в языке Pascal - имя: тип. Параметры разделены запятыми. Каждый параметр должен быть явно указан.
fun powerOf(number: Int, exponent: Int): Int { /*...*/ }
Вы можете использовать завершающую запятую при объявлении параметров функции.
fun powerOf(
number: Int,
exponent: Int, // завершающая запятая
) { /*...*/ }
Аргументы по умолчанию #
Параметры функции могут иметь значения по умолчанию, которые используются в случае, если аргумент функции не указан при её вызове. Это позволяет снизить уровень перегруженности кода
fun read(
b: ByteArray,
off: Int = 0,
len: Int = b.size,
) { /*...*/ }
Значения по умолчанию указываются после типа знаком =
Такую функцию можно вызвать без указания значения для последних аргументов
read(byteArrayOf(-0x80, -0x79, 0x00, 0x79, 0x80))
Именованные аргументы #
При вызове функции вы можете явно указать имена одного или нескольких аргументов. Это может быть полезно, когда у функции большой список аргументов, и сложно связать значение с аргументом, особенно если это логическое или null значение.
При явном указывании имен аргументов в вызове функции, вы можете свободно изменять порядок их перечисления, и, если вы хотите использовать их значения по умолчанию, вы можете просто пропустить эти аргументы.
Рассмотрим следующую функцию reformat(), которая имеет 4 аргумента со значениями по умолчанию:
fun reformat(
str: String,
normalizeCase: Boolean = true,
upperCaseFirstLetter: Boolean = true,
divideByCamelHumps: Boolean = false,
wordSeparator: Char = ' ',
) { /*...*/ }
При её вызове, вам не нужно явно указывать все имена аргументов.
reformat(
"String!",
false,
upperCaseFirstLetter = false,
divideByCamelHumps = true,
'_'
)
Вы можете пропустить все аргументы со значением по умолчанию.
reformat("This is a long String!")
Вы также можете пропустить не только все аргументы со значениями по умолчанию, но и лишь некоторые из них. Однако после первого пропущенного аргумента вы должны указывать имена всех последующих аргументов.
reformat("This is a short String!", upperCaseFirstLetter = false,
wordSeparator = '_')
Параметр по умолчанию и вызов с указанием названий аргументов #
Если параметр по умолчанию предшествует параметру без значения по умолчанию, значение по умолчанию можно использовать только при вызове функции с именованными аргументами
fun foo(
bar: Int = 0,
baz: Int,
) { /*...*/ }
foo(baz = 1) // Используется значение по умолчанию bar = 0
Функции с возвращаемым типом Unit #
Если функция не возвращает никакого полезного значения, её возвращаемый тип - Unit. Unit - тип только с одним значением - Unit. Это значение не нуждается в явном указании возвращения функции.
fun printHello(name: String?): Unit {
if (name != null)
println("Hello $name")
else
println("Hi there!")
// `return Unit` или `return` необязательны
}
Указание типа Unit в качестве возвращаемого значения тоже не является обязательным. Код, написанный выше, и следующий код совершенно идентичны:
fun printHello(name: String?) { /*...*/ }
Функции с хвостовой рекурсией #
Kotlin поддерживает стиль функционального программирования, известный как “хвостовая рекурсия”
Это позволяет использовать циклические алгоритмы вместо рекурсивных функции, но без риска переполнения стэка
Когда функция помечена модификатором tailrec и её форма отвечает требованиям компилятора, он оптимизирует рекурсию, оставляя вместо неё быстрое и эффективное решение этой задачи, основанное на циклах
val eps = 1E-10 // этого достаточно, может быть 10^-15
tailrec fun findFixPoint(x: Double = 1.0): Double =
if (Math.abs(x - Math.cos(x)) < eps) x else findFixPoint(Math.cos(x))