Kotlin передать функцию как параметр
Перейти к содержимому

Kotlin передать функцию как параметр

  • автор:

Kotlin передать функцию как параметр

Функции высокого порядка (high order function) — это функции, которые либо принимают функцию в качестве параметра, либо возвращают функцию, либо и то, и другое.

Функция как параметр функции

Чтобы функция могла принимать другую функцию через параметр, этот параметр должен представлять тип функции:

fun main() < displayMessage(::morning) displayMessage(::evening) >fun displayMessage(mes: () -> Unit) < mes() >fun morning() < println("Good Morning") >fun evening()

В данном случае функция displayMessage() через параметр mes принимает функцию типа () -> Unit , то есть такую функцию, которая не имеет параметров и ничего не возвращает.

fun displayMessage(mes: () -> Unit)

При вызове этой функции мы можем передать этому параметру функцию, которая соответствует этому типу:

displayMessage(::morning)

Рассмотрим пример параметра-функции, которая принимает параметры:

fun main() < action(5, 3, ::sum) // 8 action(5, 3, ::multiply) // 15 action(5, 3, ::subtract) // 2 >fun action (n1: Int, n2: Int, op: (Int, Int)-> Int) < val result = op(n1, n2) println(result) >fun sum(a: Int, b: Int): Int < return a + b >fun subtract(a: Int, b: Int): Int < return a - b >fun multiply(a: Int, b: Int): Int

Здесь функция action принимает три параметра. Первые два параметра - значения типа Int. А третий параметр представляет функцию, которая имеет тип (Int, Int)-> Int , то есть принимает два числа и возвращает некоторое число.

В самой функции action вызываем эту параметр-функцию, передавая ей два числа, и полученный результат выводим на консоль.

При вызове функции action мы можем передать для ее третьего параметра конкретную функцию, которая соответствует этому параметру по типу:

action(5, 3, ::sum) // 8 action(5, 3, ::multiply) // 15 action(5, 3, ::subtract) // 2

Возвращение функции из функции

В более редких случаях может потребоваться возвратить функцию из другой функции. В этом случае для функции в качестве возвращаемого типа устанавливается тип другой функции. А в теле функции возвращается лямбда выражение. Например:

fun main() < val action1 = selectAction(1) println(action1(8,5)) // 13 val action2 = selectAction(2) println(action2(8,5)) // 3 >fun selectAction(key: Int): (Int, Int) -> Int < // определение возвращаемого результата when(key)< 1 ->return ::sum 2 -> return ::subtract 3 -> return ::multiply else -> return ::empty > > fun empty (a: Int, b: Int): Int < return 0 >fun sum(a: Int, b: Int): Int < return a + b >fun subtract(a: Int, b: Int): Int < return a - b >fun multiply(a: Int, b: Int): Int

Здесь функция selectAction принимает один параметр - key, который представляет тип Int . В качестве возвращаемого типа у функции указан тип (Int, Int) -> Int . То есть selectAction будет возвращать некую функцию, которая принимает два параметра типа Int и возвращает объект типа Int.

В теле функции selectAction в зависимости от значения параметра key возвращается определенная функция, которая соответствует типу (Int, Int) -> Int .

Далее в функции main определяется переменная action1 хранит результат функции selectAction . Так как selectAction() возвращает функцию, то и переменная action1 будет хранить эту функцию. Затем через переменную action1 можно вызвать эту функцию.

Поскольку возвращаемая функция соответствует типу (Int, Int) -> Int , то при вызове в action1 необходимо передать два числа, и соответственно мы можем получить результат и вывести его на консоль.

Функциональное программирование

Одним из строительных блоков программы являются функции. Функция определяет некоторое действие. В Kotlin функция объявляется с помощью ключевого слова fun , после которого идет название функции. Затем после названия в скобках указывается список параметров. Если функция возвращает какое-либо значение, то после списка параметров через запятую можно указать тип возвращаемого значения. И далее в фигурных скобках идет тело функции.

fun имя_функции (параметры) : возвращаемый_тип

Например, определим и вызовем функцию, которая просто выводит некоторую строку на консоль:

fun main() < hello() // вызов функции hello hello() // вызов функции hello hello() // вызов функции hello >// определение функции hello fun hello()

Функции можно определять в файле вне других функций или классов, сами по себе, как например, определяется функция main. Такие функции еще называют функциями верхнего уровня (top-level functions).

Здесь кроме главной функции main также определена функция hello, которая не принимает никаких параметров и ничего не возвращает. Она просто выводит строку на консоль.

Функция hello (и любая другая определенная функция, кроме main) сама по себе не выполняется. Чтобы ее выполнить, ее надо вызвать. Для вызова функции указывается ее имя (в данном случае "hello"), после которого идут пустые скобки.

Таким образом, если необходимо в разных частях программы выполнить одни и те же действия, то можно эти действия вынести в функцию, и затем вызывать эту функцию.

Предача параметров

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

fun main() < showMessage("Hello Kotlin") showMessage("Привет Kotlin") showMessage("Salut Kotlin") >fun showMessage(message: String)

Функция showMessage() принимает один параметр типа String . Поэтому при вызове функции в скобках необходимо передать значение для этого параметра: showMessage("Hello Kotlin") . Причем это значение должно представлять тип String, то есть строку. Значения, которые передаются параметрам функции, еще назвают аргументами.

Консольный вывод программы:

Hello Kotlin Привет Kotlin Salut Kotlin

Другой пример - функция, которая выводит данные о пользователе на консоль:

fun main() < displayUser("Tom", 23) displayUser("Alice", 19) displayUser("Kate", 25) >fun displayUser(name: String, age: Int)

Функция displayUser() принимает два параметра - name и age. При вызове функции в скобках ей передаются значения для этих параметров. При этом значения передаются параметрам по позиции и должны соответствовать параметрам по типу. Так как вначале идет параметр типа String , а потом параметр типа Int , то при вызове функции в скобках вначале передается строка, а потом число.

Аргументы по умолчанию

В примере выше при вызове функций showMessage и displayUser мы обязательно должны предоставить для каждого их параметра какое-то определенное значение, которое соответствует типу параметра. Мы не можем, к примеру, вызвать функцию displayUser, не передав ей аргументы для параметров, это будет ошибка:

displayUser()

Однако мы можем определить какие-то параметры функции как необязательные и установить для них значения по умолчанию:

fun displayUser(name: String, age: Int = 18, position: String="unemployed") < println("Name: $name Age: $age Position: $position") >fun main()

В данном случае функция displayUser имеет три параметра для передачи имени, возраста и должности. Для первого параметр name значение по умолчанию не установлено, поэтому для него значение по-прежнему обязательно передавать значение. Два последующих - age и position являются необязательными, и для них установлено значение по умолчанию. Если для этих параметров не передаются значения, тогда параметры используют значения по умолчанию. Поэтому для этих параметров в принципе нам необязательно передавать аргументы. Но если для какого-то параметра определено значение по умолчанию, то для всех последующих параметров тоже должно быть установлено значение по умолчанию.

Консольный вывод программы

Name: Tom Age: 23 Position: Manager Name: Alice Age: 21 Position: unemployed Name: Kate Age: 18 Position: unemployed

Именованные аргументы

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

fun main()

При вызове функции в скобках мы можем указать название параметра и с помощью знака равно передать ему нужное значение.

При этом, как видно из последнего случае, необязательно все аргументы передавать по имени. Часть аргументов могут передаваться параметрам по позиции. Но если какой-то аргумент передан по имени, то остальные аргументы после него также должны передаваться по имени соответствующих параметров.

Также если до обязательного параметра функции идут необязательные параметры, то для обязательного параметра значение передается по имени:

fun displayUser(age: Int = 18, name: String) < println("Name: $name Age: $age") >fun main()

Изменение параметров

По умолчанию все параметры функции равносильны val-переменным, поэтому их значение нельзя изменить. Например, в случае следующей функции при компиляции мы получим ошибку:

fun double(n: Int) < n = n * 2 // !Ошибка - значение параметра нельзя изменить println("Значение в функции double: $n") >

Однако если параметр предствляет какой-то сложный объект, то можно изменять отдельные значения в этом объекте. Например, возьмем функцию, которая в качестве параметра принимает массив:

fun double(numbers: IntArray)< numbers[0] = numbers[0] * 2 println("Значение в функции double: $") > fun main() < var nums = intArrayOf(4, 5, 6) double(nums) println("Значение в функции main: $") >

Здесь функция double принимает числовой массив и увеличивает значение его первого элемента в два раза. Причем изменение элемента массива внутри функции приведет к тому, что также будет изменено значение элемента в том массиве, который передается в качестве аргумента в функцию, так как этот один и тот же массив. Консольный вывод:

Значение в функции double: 8 Значение в функции main: 8

Как вызвать функцию с параметром в другой функции в kotlin

У меня есть функция, которая возвращает некоторое значение. В параметре функции я передаю то же значение:

 fun getValue (value:String):String

Как я могу вызвать функцию getValue в другой функции? Например:

fun getResult ()

Отслеживать
17.9k 11 11 золотых знаков 25 25 серебряных знаков 58 58 бронзовых знаков
задан 28 дек 2020 в 9:19
223 1 1 серебряный знак 6 6 бронзовых знаков
А чем не устраивает var a = getValue("Hello")? Или Вам нужно передать функцию в параметре?
28 дек 2020 в 9:31

@ Crush, Мне нужно ,что бы в результате было: a =message . т е мне нужно получить значение, которое возвращает функция getValue

28 дек 2020 в 9:38

ну по логике ведь нужно что-то передать в getValue, либо можно засетить дефолтные значения но тогда результат будет, так же не очень понятно где используется переменная value после присвоения ей значения

Функции в программировании

Мы уже не раз сталкивались с функциями, вызывая их в своих программах. Это были встроенные в стандартную библиотеку Kotlin функции, код которых нас не интересовал. Нам было не важно как они работают, достаточно было знать как их вызвать, и что они в итоге делают.

Когда же подходящей нам встроенной функции нет, мы всегда можем написать свою. Такие функции называют пользовательскими. По-сути функция в программировании представляет собой кусок программного кода, выполняющий определенную задачу и вызываемый, когда требуется, по имени.

Функции, как и циклы, позволяют многократно делать одно и то же. Однако, если тело цикла выполняется сразу множество раз подряд, тело функции исполняется однажды. Просто мы может затребовать ее исполнение в разное время и из разных мест программы, обратившись к функции по имени, то есть вызвав ее. Кроме того, поведение одной и той же функции можно менять, передавая в нее разные аргументы.

Объявление функции в Kotlin начинается с ключевого слова fun , за которым идет имя функции, после которого в круглых скобках указываются параметры. Тело функции заключается в фигурные скобки.

import kotlin.random.Random fun main() { val nums: ArrayInt> = Array(10, {it}) printArray(nums) fillArray(nums, 0, 3) printArray(nums) } fun printArray(a: ArrayInt>) { for (i in a) print(" $i ") println() } fun fillArray(a: ArrayInt>, low: Int, high: Int) { for (i in a.indices) a[i] = Random.nextInt(low, high) }

Пример выполнения программы:

0 1 2 3 4 5 6 7 8 9 1 0 0 1 2 1 1 0 0 1

В программе, не считая главной функции main() , определены еще две – printArray() и fillArray() . Первая выводит массив на экран в определенном формате, вторая – заполняет массив случайными числами. Исходно, с помощью выражения Array(10, ) , массив был заполнен индексами самого массива.

В теле main() мы два раза вызываем printArray() и один раз fillArray() .

Когда функция вызывается, поток выполнения программы переходит из места ее вызова к месту ее определения и начинает выполнять тело уже этой, вызванной, функции. Когда тело функции выполнено, поток выполнения программы возвращается в то место, откуда функция вызывалась. Точнее, сразу после места вызова функции.

В нашем примере функция printArray() имеет один параметр – это переменная a типа Array . Параметры функции указываются в круглых скобках в заголовке. Если параметров несколько, как в случае с fillArray() , то между собой они разделяются запятыми. Параметров у функции может не быть.

Когда функция вызывается, то в нее передаются аргументы. Количество и тип аргументов должен соответствовать количеству и типам параметров функции. Таким образом, a – это переменная-параметр функции. Переменная nums – это аргумент, передаваемый в функцию.

На самом деле в функцию передается не сама переменная nums . Ни fillArray() , ни printArray() ничего не знают об этой переменной. Если вы попробуете оттуда обратиться к ней за ее значением, получите ошибку.

Локальная переменная недоступна из другой функции

Unresolved reference – неразрешимая ссылка, функции непонятно, на что ссылается переменная nums , для нее nums не существует. IntelliJ IDEA предлагает создать в функции собственную локальную версию nums . Если так сделать, это будет другая nums , а не та, что в функции main() .

Как же массив, определенный в одной функции, оказывается в другой? Массив – это объект в памяти. Переменная nums играет роль указателя, ссылки на него. Когда мы вызываем функцию printArray() и в скобках записываем nums , то на самом деле в функцию передается не переменная, связанная с объектом, а ссылка на этот объект. Уже в функции эта ссылка связывается с параметром-переменной a .

Таким образом, на один и тот же объект в памяти указывают уже две переменные – nums в функции main() и a – в printArray() . Это сравнимо с тем, как на одно и то же место могут указывать разные указатели, расположенные в разных местах.

Если мы меняем объект, как это происходит в функции fillArray() , через одну переменную, то обратившись к этому объекту через другую, увидим эти изменения. Объект-то один.

Иначе обстоит дело, когда передаются неизменяемые типы, в том числе примитивные. Тут либо из переменной-аргумента в переменную-параметр копируется непосредственно значение, то есть в памяти появляются, например, два числа, либо все же копируется ссылка. Но в таком случае поскольку объект изменять нельзя, никаких изменений с ним в функции не произойдет по определению. Более того, параметры в Kotlin – это val переменные, то есть им нельзя присваивать новое значение.

В Kotlin параметры функций относятся к неизменяемым переменным

С другой стороны, из функций можно возвращать значения, которые могут быть присвоены переменным в том месте программы, откуда функция вызывалась. Например, когда мы вызывали функцию readln() , то присваивали то, что она возвращает, переменной.

val s = readln()

Для возврата значения из функции используется оператор return . Чтобы в объявлении функции показать, что она возвращает определенный тип данных, в заголовке после круглых скобок ставят двоеточие и указывают возвращаемый тип.

fun main() { val num = readln().toInt() val sumDigits = countDig(num) println(sumDigits) } fun countDig(int: Int): Int { var i = int var sum = 0 while (i > 0) { sum = sum + i % 10 i = i / 10 } return sum }

Пример выполнения программы:

378 18

Функция countDig() считает сумму цифр переданного ей числа и возвращает ее из себя. Знак процента по отношению к целочисленным операндам выполняет операцию нахождения остатка от деления первого на второй. При таком делении на 10 извлекается последняя цифра числа (i % 10) . Далее добавляем ее к сумме, а полученное новое значение присваиваем переменной sum . Операция деления по отношению к целым числам делит их нацело, то есть выражение i / 10 избавляет i от последней цифры, которая уже была добавлена к сумме.

Выражение return sum осуществляет выход из функции и передачу в место вызова функции значения переменной sum . Там это значение может быть присвоено своей локальной переменной. Так в программе выше результат работы countDig() присваивается переменной sumDigits .

На самом деле в Kotlin не существует функций, которые вообще ничего не возвращают. Если функция явно не возвращает из себя никаких значений, значит по-умолчанию она возвращает объект Unit , что можно трактовать как "ничего", однако путать его с null не следует.

Мы можем присвоить этот объект переменной, хотя смысла в этом нет.

Функции в Kotlin по-умолчанию возвращают объект Unit

Практическая работа:

Напишите функцию, которой в качестве аргумента передается массив, и из которой возвращается словарь, в котором индексы массива становятся ключами, а элементы массива – значениями.

X Скрыть Наверх

Kotlin с нуля. Курс для начинающих

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *