Функции в Kotlin
#
Васильев Андрей Михайлович, 2024
Версии презентации
Определение фукнции
#
В Kotlin функции объявляются с помощью ключевого слова fun
fun double(x: Int): Int {
return 2 * x
}
- Функция обычно начинается со строчной буквы
- Слова в названии выделяютс с помощью camelCase, 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))