Функции в Kotlin

Функции в 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))

© A. M. Васильев, 2024, CC BY-SA 4.0, andrey@crafted.su