High-Order_functions_and_lambdas

Higher-Order Functions and Lambdas1

Higher-Order Functions

A higher-order function is a function that takes functions as parameters, or returns a function.

fun <T, R> Collection<T>.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
}

如上述方法的combine參數,其類型爲(R,T)->T;

調用上述方法,使用lambda表達式傳入combine參數:

val items = listOf(1, 2, 3, 4, 5)

// Lambdas are code blocks enclosed in curly braces.
items.fold(0, { 
    // When a lambda has parameters, they go first, followed by '->'
    acc: Int, i: Int -> 
    print("acc = $acc, i = $i, ") 
    val result = acc + i
    println("result = $result")
    // The last expression in a lambda is considered the return value:
    result
})

// Parameter types in a lambda are optional if they can be inferred:
val joinedToString = items.fold("Elements:", { acc, i -> acc + " " + i })

// Function references can also be used for higher-order function calls:
val product = items.fold(1, Int::times)

運行結果如下:

acc = 0, i = 1, result = 1
acc = 1, i = 2, result = 3
acc = 3, i = 3, result = 6
acc = 6, i = 4, result = 10
acc = 10, i = 5, result = 15
joinedToString = Elements: 1 2 3 4 5
product = 120

Function types

eg.(Int) -> String val onClick: () -> Unit = ...

聲明函數類型時可以指定參數名: (x: Int, y: Int) -> Point. 如x,y

You can also give a function type an alternative name by using a type alias:

Instantiating a function type

There are several ways to obtain an instance of a function type:

  1. Using a code block within a function literal, in one of the forms:

    Function literals with receiver can be used as values of function types with receiver.

  2. Using a callable reference to an existing declaration:

    • a top-level, local, member, or extension function: ::isOdd, String::toInt,
    • a top-level, member, or extension property: List::size,
    • a constructor: ::Regex

    These include bound callable references that point to a member of a particular instance: foo::toString.

  3. Using instances of a custom class that implements a function type as an interface:

class IntTransformer: (Int) -> Int {
    override operator fun invoke(x: Int): Int = TODO()
}

val intFunction: (Int) -> Int = IntTransformer()

Non-literal values of function types with and without receiver are interchangeable, so that the receiver can stand in for the first parameter, and vice versa. For instance, a value of type (A, B) -> C can be passed or assigned where a A.(B) -> C is expected and the other way around:

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

Invoking a function type instance

A value of a function type can be invoked by using its invoke(…) operator: f.invoke(x) or just f(x).

If the value has a receiver type, the receiver object should be passed as the first argument. Another way to invoke a value of a function type with receiver is to prepend it with the receiver object, as if the value were an extension function: 1.foo(2),

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)) // extension-like call

  1. Higher-Order Functions and Lambdas ↩︎

發佈了107 篇原創文章 · 獲贊 87 · 訪問量 58萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章