Kotlin Notes - 4

发布时间 2023-11-21 23:04:05作者: Otlpy
  1. 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
    }
    

    To call fold, you need to pass an instance of the function type to it as an argument, and lambda expressions are widely used for this purpose at higher-order function call sites:

    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)
    
  2. Kotlin uses function types, such as (Int) -> String, for declarations that deal with functions: val onClick: () -> Unit = ....

  3. The full syntactic form of lambda expressions is as follows:

    val sum: (Int, Int) -> Int = { x: Int, y: Int -> x + y }
    

    If you leave all the optional annotations out, what's left looks like this:

    val sum = { x: Int, y: Int -> x + y }
    
  4. According to Kotlin convention, if the last parameter of a function is a function, then a lambda expression passed as the corresponding argument can be placed outside the parentheses:

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

    If the lambda is the only argument in that call, the parentheses can be omitted entirely:

    run { println("...") }
    
  5. it: implicit name of a single parameter

    If the compiler can parse the signature without any parameters, the parameter does not need to be declared and -> can be omitted. The parameter will be implicitly declared under the name it:

    ints.filter { it > 0 } // this literal is of type '(it: Int) -> Boolean'
    
  6. You can explicitly return a value from the lambda using the qualified return syntax. Otherwise, the value of the last expression is implicitly returned.

    ints.filter {
        val shouldFilter = it > 0
        shouldFilter
    }
    
    ints.filter {
        val shouldFilter = it > 0
        return@filter shouldFilter
    }