Перейти к содержимому

Invoke kotlin зачем нужен

  • автор:

Лямбды

Лямбды всегда находятся внутри фигурных скобок. Слева находятся аргументы, справа — тело функции. Разделяет их специальное выражение ->. Например, создадим выражение.

  x + 5> 

Открыли фигурную скобку, записали параметр в виде числа Int, а затем указали, что с ним нужно делать в правой части — прибавить к числу 5. Параметр может быть один, как в нашем пример, несколько или вообще не быть.

Лямбда-выражение можно сохранить в переменной, а затем обращаться к ней как к обычной функции. Можно вызвать лямбда-выражение при помощи invoke().

 val lambda = < println("Hello Kitty!") >lambda.invoke() 

Лямбда-выражение может послужить удобной заменой для паттернов Listener или Callback.

Примеры

 // Нет аргументов и возвращает 1 < 1 >// () -> Int // Один аргумент в виде строки, который выводится на экран < s: String ->println(s) > // (String)->Unit // два аргумента типа Int и возвращает произведение чисел < a: Int, b: Int ->a * b > // (Int, Int)->Int 

Код с лямбдами становится короче и читабельнее.

 button.setOnClickListener < /* код для щелчка кнопки */ >
 val sum = < x: Int, y: Int ->x + y > println(sum(1, 2)) // 3 

Лямбды можно записывать в несколько строк.

 val test = < a: Int, b: Int ->println("$a + $b") a + b > 

Этот же пример можно записать одной строкой, разделяя команды точкой с запятой.

val test = < a: Int, b: Int ->println(«$a + $b»); a + b >

setOnClickListener

Рассмотрим применение лямбда-выражений на примере обработчика щелчка кнопки.

Код на Java 7 и ниже.

 button.setOnClickListener(new OnClickListener() < @Override public void onClick(View view) < /* код для щелчка кнопки */ >>); 

Если использовать такой же код на Kotlin, то получим.

 button.setOnClickListener(object : View.OnClickListener < override fun onClick(v: View?) < println("Hello Kitty") >>) 

Студия предложит сконвертировать код, используя лямбду. В моём случае студия сразу сконвертировала в самый короткий вариант. Но мы рассмотрим все случаи, например, возможен такой вариант.

 button.setOnClickListener( < v ->println("Hello Kitty") >) 

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

 button.setOnClickListener() < v ->println("Hello Kitty") > 

Если у функции несколько параметров, то только последнюю можно вынести за круглые скобки.

А мы продолжаем уменьшать код. Если у функции только один параметр и он является функцией, то круглые скобки можно убрать.

 button.setOnClickListener < v ->println("Hello Kitty") > 

Если в самом лямбда-выражении не используется параметр в левой части, то его можно удалить. Это справедливо для выражения с одним параметром. В нашем примере v (View) не используется, сокращаем код ещё раз.

 button.setOnClickListener

Функция с одним параметром. Ключевое слово it

Рассмотрим частный случай, когда функция только получает параметр. Мы можем не использовать левую часть, а использовать ключевое слово it. Например, мы используем v для его передачи другой функции.

 button.setOnClickListener < v ->doSomething(v) > private fun doSomething(v: View?)

Убираем левую часть и используем it.

 button.setOnClickListener

Все варианты в одном месте.

 button.setOnClickListener( < v ->println("Hello Kitty") >) button.setOnClickListener() < v ->println("Hello Kitty") > button.setOnClickListener < v ->println("Hello Kitty") > button.setOnClickListener < println("Hello Kitty") >button.setOnClickListener < v ->doSomething(v) > button.setOnClickListener

Другой пример использования — пройтись по элементам коллекции. Например, воспользуемся forEach:

 val cats = listOf("Barsik", "Murzik", "Ryzhik") cats.forEach < println(it) >// Выводит Barsik Murzik Ryzhik 

Без использования ключевого слова it пришлось бы писать длинный вариант.

 cats.forEach < cat ->println(cat) > 

Функции высшего порядка

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

Напишем функцию convert(), которая преобразует значение Double по формуле, передаваемой в лямбда-выражении, выводит результат и возвращает её. Например, с помощью этой функции вы сможете преобразовать температуру по Цельсию в температуру по Фаренгейту или преобразовать вес из килограммов в фунты — все зависит от формулы, которая передаётся в лямбда-выражении (аргумента). Начнём с определения параметров функции.

Для этого в функцию будут добавлены два параметра: Double и лямбда-выражение. Назовём лямбда-выражение converter, а поскольку оно будет использоваться для преобразования Double в Double, оно должно иметь тип (Double) -> Double (лямбда-выражение, которое получает параметр Double и возвращает Double).

 fun convert(x: Double, converter: (Double) -> Double) : Double < // ваш код >

Напишем какой-то для функции.

 fun convert(x: Double, converter: (Double) -> Double) : Double < val result = converter(x) println("$x is converted to $result") // выводим результат return result // вернуть результат >

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

Давайте используем функцию convert() для преобразования 20 градусов по Цельсию в градусы по Фаренгейту. Для этого функции нужно передать значения 20.0 и лямбда-выражение < c: Double ->c * 1.8 + 32 >:

 convert(20.0, < c: Double ->c * 1.8 + 32 >) // 20.0 is converted to 68.0 // с присвоением возвращаемого результата переменной val fahrenheit = convert(20.0, < c: Double ->c * 1.8 + 32 >) println(fahrenheit) 

Если последний параметр вызываемой функции является лямбда-выражением, лямбда-аргумент можно вынести за круглые скобки вызова функции.

 // было convert(20.0, < c: Double ->c * 1.8 + 32 >) // стало convert(20.0) < c: Double ->c * 1.8 + 32 > 

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

Предположим, функция convertFive() преобразует Int 5 в Double по формуле преобразования, которая передаётся в виде лямбда-выражения.

 fun convertFive(converter: (Int) -> Double) : Double
 // стандартный вариант convertFive() < it * 1.8 + 32 >// компактный вариант без круглых скобок convertFive

Функция может возвращать лямбда-выражение. Например, следующий код определяет функцию с именем getConversionLambda(), которая возвращает лямбда-выражение типа (Double) -> Double. Точное лямбда-выражение, возвращаемое функцией, зависит от значения переданной строки.

 fun getConversionLambda(str: String): (Double) -> Double < if (str == "CentigradeToFahrenheit") < return < it * 1.8 + 32 >> else if (str == "KgsToPounds") < return < it * 2.204623 >> else if (str == "PoundsToUSTons") < return < it / 2000.0 >> else < return < it >> > 

Вы можете вызвать лямбда-выражение, возвращённое функцией, или использовать его в аргументе при вызове другой функции. Например, следующий код выполняет возвращаемое значение getConversionLambda для пересчета 2,5 кг в фунты и присваивает его переменной с именем pounds:

 val pounds = getConversionLambda("KgsToPounds")(2.5) println(pounds) 

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

Перегрузка операторов

Kotlin позволяет реализовывать предопределённый набор операторов для ваших типов. Эти операторы имеют фиксированное символическое представление (вроде + или * ) и фиксированные приоритеты. Для реализации оператора предоставьте функцию-член или функцию-расширение с фиксированным именем и с соответствующим типом, т. е. левосторонним типом для бинарных операций или типом аргумента для унарных операций.

Функции, которые перегружают операторы, должны быть отмечены модификатором operator .

interface IndexedContainer

При переопределении перегрузок оператора вы можете опускать operator .

class OrdersList: IndexedContainer < override fun get(index: Int) < /*. */ >> 

Унарные операторы

Унарные префиксные операторы

Выражение Транслируется в
+a a.unaryPlus()
-a a.unaryMinus()
!a a.not()

Под транслированием, понимается представление вашего кода после компиляции.

Эта таблица демонстрирует, что компилятор при обрабатывании, к примеру, выражения +a , осуществляет следующие действия:

  • Определяет тип выражения a , пусть это будет T ;
  • Ищет функцию unaryPlus() с модификатором operator без параметров для приёмника типа Т , т. е. функцию-член или функцию-расширение;
  • Если функция отсутствует или неоднозначная, возвращается ошибка компиляции;
  • Если функция присутствует и R — её возвращаемый тип, выражение +a имеет Тип R .

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

Например, вы можете перегрузить оператор унарного минуса:

data class Point(val x: Int, val y: Int) operator fun Point.unaryMinus() = Point(-x, -y) fun main() < val point = Point(10, 20) println(-point) // выведет "Point(x=-10, y=-20)" >

Инкремент и декремент

Выражение Транслируется в
a++ a.inc() + см. ниже
a— a.dec() + см. ниже

Функции inc() и dec() должны возвращать значение, которое будет присвоено переменной, к которой была применена операция ++ или — . Они не должны изменять сам объект, для которого были вызваны эти функции.

Компилятор осуществляет следующие шаги, обрабатывая операторы в постфиксной форме, например a++ :

  • Определяет тип переменной a , пусть это будет T ;
  • Ищет функцию inc() с модификатором operator без параметров, применимую для приёмника типа Т .
  • Проверяет, что возвращаемый тип такой функции является подтипом T .

Результатами вычисления выражения является:

  • Сохранение инициализирующего значения a во временную переменную a0 ,
  • Сохранение результата выполнения a0.inc() в a ,
  • Возвращение a0 как результата вычисления выражения (т.е. значения до инкремента).

Для a— шаги выполнения полностью аналогичные.

Для префиксной формы ++a или —a действует также, но результатом будет:

  • Присвоение результата вычисления a.inc() непосредственно a ,
  • Возвращение нового значения a как результата вычисления выражения.

Бинарные операции

Арифметические операции

Выражение Транслируется в
a + b a.plus(b)
a — b a.minus(b)
a * b a.times(b)
a / b a.div(b)
a % b a.rem(b)
a..b a.rangeTo(b)

Для перечисленных в таблице операций компилятор всего лишь решает выражение из колонки Транслируется в.

Ниже приведен пример класса Counter (счетчик), начинающего счёт с заданного значения, которое может быть увеличено с помощью перегруженного оператора + :

data class Counter(val dayIndex: Int) < operator fun plus(increment: Int): Counter < return Counter(dayIndex + increment) >> 

Оператор in

Выражение Транслируется в
a in b b.contains(a)
a !in b !b.contains(a)

Для in и !in используется одна и та же процедура, только возвращаемый результат инвертируется.

Оператор доступа по индексу

Выражение Транслируется в
a[i] a.get(i)
a[i, j] a.get(i, j)
a[i_1, . i_n] a.get(i_1, . i_n)
a[i] = b a.set(i, b)
a[i, j] = b a.set(i, j, b)
a[i_1, . i_n] = b a.set(i_1, . i_n, b)

Квадратные скобки транслируются в вызов get или set с соответствующим числом аргументов.

Оператор вызова

Выражение Транслируется в
a() a.invoke()
a(i) a.invoke(i)
a(i, j) a.invoke(i, j)
a(i_1, . i_n) a.invoke(i_1, . i_n)

Оператор вызова (функции, метода) в круглых скобках транслируется в invoke с соответствующим числом аргументов.

Присвоения с накоплением

Выражение Транслируется в
a += b a.plusAssign(b)
a -= b a.minusAssign(b)
a *= b a.timesAssign(b)
a /= b a.divAssign(b)
a %= b a.modAssign(b)

Для присваивающих операций, таких как a += b , компилятор осуществляет следующие шаги:

  • Если функция из правой колонки таблицы доступна:
    • Если соответствующая бинарная функция (например plus() для plusAssign() ) также доступна, a — изменяемая переменная и возвращаемый тип plus является подтипом типа a , то фиксируется ошибка (неоднозначность);
    • Проверяется, что возвращаемое значение функции Unit , в противном случае фиксируется ошибка;
    • Генерируется код для a.plusAssign(b) .

    Присвоение НЕ ЯВЛЯЕТСЯ выражением в Kotlin.

    Операторы равенства и неравенства

    Выражение Транслируется в
    a == b a?.equals(b) ?: (b === null)
    a != b !(a?.equals(b) ?: (b === null))

    Эти операторы работают только с функцией equals(other: Any?): Boolean , которая может быть переопределена для обеспечения пользовательской реализации проверки равенства. Любая другая функция с тем же именем (например, equals(other: Foo) ) вызываться не будет.

    `===` and `!==` (identity checks) are not overloadable, so no conventions exist for them. —>

    Операции === и !== (проверка идентичности) являются неперегружаемыми, поэтому никакие соглашения для них не приводятся.

    Операция == имеет специальный смысл: она транслируется в составное выражение, в котором экранируются значения null . null == null — это всегда истина, а x == null для non-null значений x — всегда ложь, и не будет расширяться в x.equals() .

    Операторы сравнений

    Выражение Транслируется в
    a > b a.compareTo(b) > 0
    a < b a.compareTo(b) < 0
    a >= b a.compareTo(b) >= 0
    a

    a.compareTo(b)

    Все сравнения транслируются в вызовы compareTo , от которых требуется возврат значения типа Int .

    Операторы делегирования свойств

    Операторы provideDelegate , getValue и setValue описаны в Делегированные свойства.

    Инфиксные вызовы именованных функций

    Вы можете имитировать инфиксные операции, используя инфиксную запись.

    © 2015—2024 Open Source Community

    Высокоуровневые функции и лямбды

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

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

    Функции высшего порядка

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

    Хорошим примером такой функции является идиома функционального программирования fold для коллекций, которая принимает начальное значение — accumulator вместе с комбинирующей функцией и строит возвращаемое значение, последовательно комбинируя текущее значение accumulator с каждым элементом коллекции, заменяя значение accumulator .

    fun Collection.fold( initial: R, combine: (acc: R, nextElement: T) -> R ): R < var accumulator: R = initial for (element: T in this) < accumulator = combine(accumulator, element) >return accumulator > 

    R`, so it accepts a function that takes two arguments of types `R` and `T` and returns a value of type `R`. It is [invoked](#invoking-a-function-type-instance) inside the `for` loop, and the return value is then assigned to `accumulator`. —>

    В приведённом выше коде параметр combine имеет функциональный тип (R, T) -> R , поэтому он принимает функцию, которая принимает два аргумента типа R и T и возвращает значение типа R . Он вызывается внутри цикла for и присваивает accumulator возвращаемое значение.

    Чтобы вызвать fold , вы должны передать ему экземпляр функционального типа в качестве аргумента и лямбда-выражение (описание ниже). Лямбда-выражения часто используются в качестве параметра функции высшего порядка.

    fun main() < val items = listOf(1, 2, 3, 4, 5) // Лямбда - это блок кода, заключенный в фигурные скобки. items.fold(0, < // Если у лямбды есть параметры, то они указываются перед знаком '->' acc: Int, i: Int -> print("acc = $acc, i = $i, ") val result = acc + i println("result = $result") // Последнее выражение в лямбде считается возвращаемым значением: result >) // Типы параметров в лямбде необязательны, если они могут быть выведены: val joinedToString = items.fold("Elements:", < acc, i ->acc + " " + i >) // Ссылки на функции также могут использоваться для вызовов функций высшего порядка: val product = items.fold(1, Int::times) println("joinedToString = $joinedToString") println("product = $product") > 

    Функциональные типы

    String`, for declarations that deal with functions: `val onClick: () -> Unit = . `. —>

    Kotlin использует семейство функциональных типов, таких как (Int) -> String , для объявлений, которые являются частью функций: val onClick: () -> Unit = . .

    Эти типы имеют специальные обозначения, которые соответствуют сигнатурам функций, то есть их параметрам и возвращаемым значениям:

    • У всех функциональных типов есть список с типами параметров, заключенный в скобки, и возвращаемый тип: (A, B) -> C обозначает тип, который предоставляет функции два принятых аргумента типа A и B , а также возвращает значение типа C . Список с типами параметров может быть пустым, как, например, в () -> A . Возвращаемый тип Unit не может быть опущен;
    • У функциональных типов может быть дополнительный тип — получатель (ориг.: receiver), который указывается в объявлении перед точкой: тип A.(B) -> C описывает функции, которые могут быть вызваны для объекта-получателя A с параметром B и возвращаемым значением C . Литералы функций с объектом-приёмником часто используются вместе с этими типами;
    • Останавливаемые функции (ориг.: suspending functions) принадлежат к особому виду функциональных типов, у которых в объявлении присутствует модификатор suspend , например, suspend () -> Unit или suspend A.(B) -> C .

    Объявление функционального типа также может включать именованные параметры: (x: Int, y: Int) -> Point . Именованные параметры могут быть использованы для описания смысла каждого из параметров.

    Чтобы указать, что функциональный тип может быть nullable, используйте круглые скобки: ((Int, Int) -> Int)? .

    При помощи круглых скобок функциональные типы можно объединять: (Int) -> ((Int) -> Unit) .

    The arrow notation is right-associative, `(Int) -> (Int) -> Unit` is equivalent to the previous example, but not to `((Int) -> (Int)) -> Unit`. —>

    Стрелка в объявлении является правоассоциативной (ориг.: right-associative), т.е. объявление (Int) -> (Int) -> Unit эквивалентно объявлению из предыдущего примера, а не ((Int) -> (Int)) -> Unit .

    Вы также можете присвоить функциональному типу альтернативное имя, используя псевдонимы типов.

    typealias ClickHandler = (Button, ClickEvent) -> Unit 

    Создание функционального типа

    Существует несколько способов получить экземпляр функционального типа:

    • Используя блок с кодом внутри функционального литерала в одной из форм:
      • лямбда-выражение: < a, b ->a + b > ,
      • анонимная функция: fun(s: String): Int

      Литералы функций с объектом-приёмником могут использоваться как значения функциональных типов с получателем.

      • Используя вызываемую ссылку на существующее объявление:
        • функции верхнего уровня, локальной функции, функции-члена или функции-расширения: ::isOdd , String::toInt ,
        • свойства верхнего уровня, члена или свойства-расширения: List::size ,
        • конструктора: ::Regex

        К ним относятся привязанные вызываемые ссылки, которые указывают на член конкретного экземпляра: foo::toString .

        • Используя экземпляр пользовательского класса, который реализует функциональный тип в качестве интерфейса:
        class IntTransformer: (Int) -> Int < override operator fun invoke(x: Int): Int = TODO() >val intFunction: (Int) -> Int = IntTransformer() 

        При достаточной информации компилятор может самостоятельно вывести функциональный тип для переменной.

        val a = < i: Int ->i + 1 > // Выведенный тип - (Int) -> Int 

        C` can be passed or assigned where a value of type `A.(B) -> C` is expected, and the other way around: —>

        Небуквальные (ориг.: non-literal) значения функциональных типов с и без получателя являются взаимозаменяемыми, поэтому получатель может заменить первый параметр, и наоборот. Например, значение типа (A, B) -> C может быть передано или назначено там, где ожидается A.(B) -> C , и наоборот.

        fun main() < val repeatFun: String.(Int) ->String = < times ->this.repeat(times) > val twoParameters: (String, Int) -> String = repeatFun // OK fun runTransformation(f: (String, Int) -> String): String < return f("hello", 3) >val result = runTransformation(repeatFun) // OK println("result = $result") > 

        A function type with no receiver is inferred by default, even if a variable is initialized with a reference > to an extension function. > To alter that, specify the variable type explicitly. —>

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

        Вызов экземпляра функционального типа

        Значение функционального типа может быть вызвано с помощью оператора invoke(. ) : f.invoke(x) или просто f(x) .

        Если значение имеет тип получателя, то объект-приёмник должен быть передан в качестве первого аргумента. Другой способ вызвать значение функционального типа с получателем — это добавить его к объекту-приёмнику, как если бы это была функция-расширение: 1.foo(2) .

        fun main() < val stringPlus: (String, String) ->String = String::plus val intPlus: Int.(Int) -> Int = Int::plus println(stringPlus.invoke("")) println(stringPlus("Hello, ", "world!")) println(intPlus.invoke(1, 1)) println(intPlus(1, 2)) println(2.intPlus(3)) // вызывается как функция-расширение > 

        Встроенные функции

        Иногда выгодно улучшить производительность функций высшего порядка, используя встроенные функции (ориг.: inline functions).

        Лямбда-выражения и анонимные функции

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

        max(strings, < a, b ->a.length < b.length >) 

        Функция max является функцией высшего порядка, потому что она принимает функцию в качестве второго аргумента. Этот второй аргумент является выражением, которое в свою очередь есть функция, то есть функциональный литерал. Как функция он эквивалентен объявлению:

        fun compare(a: String, b: String): Boolean = a.length < b.length 

        Синтаксис лямбда-выражений

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

        val sum: (Int, Int) -> Int = < x: Int, y: Int ->x + y > 
        • Лямбда-выражение всегда заключено в скобки ;
        • Объявление параметров при таком синтаксисе происходит внутри этих скобок и может включать в себя аннотации типов;
        • Тело функции начинается после знака -> ;
        • Если тип возвращаемого значения не Unit , то в качестве возвращаемого типа принимается последнее (а возможно и единственное) выражение внутри тела лямбды.

        Если вы вынесите все необязательные объявления, то, что останется, будет выглядеть следующим образом:

        val sum = < x: Int, y: Int ->x + y > 

        Передача лямбды в качестве последнего параметра

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

        val product = items.fold(1) < acc, e ->acc * e > 

        Такой синтаксис также известен как trailing lambda.

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

        it: неявное имя единственного параметра

        Очень часто лямбда-выражение имеет только один параметр.

        ` can be omitted. The parameter will be implicitly declared under the name `it`: -->

        Если компилятор способен самостоятельно определить сигнатуру, то объявление параметра можно опустить вместе с -> . Параметр будет неявно объявлен под именем it .

        ints.filter < it >0 > // этот литерал имеет тип '(it: Int) -> Boolean' 

        Возвращение значения из лямбда-выражения

        Вы можете вернуть значение из лямбды явно, используя оператор return. Либо неявно будет возвращено значение последнего выражения.

        Таким образом, два следующих фрагмента равнозначны:

        ints.filter < val shouldFilter = it >0 shouldFilter > ints.filter < val shouldFilter = it >0 return@filter shouldFilter > 

        Это соглашение, вместе с передачей лямбда-выражения вне скобок, позволяет писать код в стиле LINQ.

        strings.filter < it.length == 5 >.sortedBy < it >.map

        Символ подчеркивания для неиспользуемых переменных

        Если параметр лямбды не используется, то разрешено его имя заменить на символ подчёркивания.

        map.forEach < _, value ->println("$value!") > 

        Деструктуризация в лямбдах

        Деструктуризация в лямбдах описана в Деструктурирующие объявления.

        Анонимные функции

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

        fun(x: Int, y: Int): Int = x + y 

        Объявление анонимной функции выглядит очень похоже на обычное объявление функции, за исключением того, что её имя опущено. Тело такой функции может быть описано и выражением (как показано выше), и блоком.

        fun(x: Int, y: Int): Int

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

        ints.filter(fun(item) = item > 0) 

        Аналогично и с типом возвращаемого значения: он вычисляется автоматически для функций-выражений или же должен быть явно определён (если не является типом Unit ) для анонимных функций с блоком в качестве тела.

        When passing anonymous functions as parameters, place them inside the parentheses. The shorthand syntax that allows you to leave > the function outside the parentheses works only for lambda expressions. -->

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

        Одним из отличий лямбда-выражений от анонимных функций является поведение оператора return (non-local returns). Слово return , не имеющее метки ( @ ), всегда возвращается из функции, объявленной ключевым словом fun . Это означает, что return внутри лямбда-выражения возвратит выполнение к функции, включающей в себя это лямбда-выражение. Внутри анонимных функций оператор return , в свою очередь, выйдет, собственно, из анонимной функции.

        Замыкания

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

        var sum = 0 ints.filter < it >0 >.forEach < sum += it >print(sum) 

        Литералы функций с объектом-приёмником

        C`, can be instantiated with a special form of function literals – function literals with receiver. -->

        Функциональные типы с получателем, такие как A.(B) -> C , могут быть вызваны с помощью особой формы – литералов функций с объектом-приёмником.

        Как было сказано выше, Kotlin позволяет вызывать экземпляр функционального типа с получателем, предоставляющим объект-приёмник.

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

        Это схоже с принципом работы функций-расширений, которые позволяют получить доступ к членам объекта-приёмника внутри тела функции.

        Ниже приведён пример литерала с получателем вместе с его типом, где plus вызывается для объекта-приёмника:

        val sum: Int.(Int) -> Int = < other ->plus(other) > 

        Синтаксис анонимной функции позволяет вам явно указать тип приёмника. Это может быть полезно в случае, если вам нужно объявить переменную типа нашей функции для использования в дальнейшем.

        val sum = fun Int.(other: Int): Int = this + other 

        Лямбда-выражения могут быть использованы как литералы функций с приёмником, когда тип приёмника может быть выведен из контекста. Один из самых важных примеров их использования это типобезопасные строители (ориг.: type-safe builders).

        class HTML < fun body() < . >> fun html(init: HTML.() -> Unit): HTML < val html = HTML() // создание объекта-приёмника html.init() // передача приёмника в лямбду return html >html < // лямбда с приёмником начинается тут body() // вызов метода объекта-приёмника >

        Invoke kotlin зачем нужен

        Комментарии

        Популярные По порядку
        Не удалось загрузить комментарии.

        ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ

        10 полезных книг для Java программиста на русском языке

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

        Зачем учить язык Kotlin?

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

        20 отличных ресурсов для изучения Kotlin

        Данная подборка материалов связана с изучением нового, и теперь уже официального языка Android-разработки Kotlin. Изучив данную подборку, возможно, вам захочется узнать о Kotlin больше!

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

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