TIL

Higher-order functions and lambdas

Higher-order functions

fun <T, R> Collection<T>.fold(
    initial: R,
    combine: (acc: R, nextElement: T) -> R
): R {
    // ...
}
val joinedToString = items.fold("Elements:", { acc, i -> acc + " " + i })

Function types

Instantiating a function type

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

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

Invoking a function type instance

Inline functions

Lambda expressions and anonymous functions

// max는 함수를 인자로 받기에 고차 함수
max(strings, { a, b -> a.length < b.length })

Lambda expression syntax

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

Passing trailing lambdas

run { println("...") }

it: implicit name of a single parameter

ints.filter { it > 0 } // '(it: Int) -> Boolean'

Returning a value from a lambda expression

// 아래 두 표현은 같다
ints.filter {
    val shouldFilter = it > 0
    shouldFilter
}

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

Underscore for unused variables

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

Destructuring in lambdas

map.mapValues { (key, value) -> "$value!" }

Anonymous functions

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

fun(x: Int, y: Int): Int {
    return x + y
}
// 람다식에서의 non-local return 예시
fun lambdaTest() {
    listOf(1, 2, 3).forEach {
        if (it == 2) return  // lambdaTest 함수 전체를 종료시킴 (non-local return)
        println(it)
    }
    println("이 문장은 출력되지 않음")
}

// 익명 함수에서의 return 예시
fun anonymousFuncTest() {
    listOf(1, 2, 3).forEach(fun(value) {
        if (value == 2) return  // 익명 함수만 종료, forEach는 계속됨 (local return)
        println(value)
    })
    println("이 문장은 정상적으로 출력됨")
} 

Closures

var sum = 0
ints.filter { it > 0 }.forEach {
    sum += it // 외부 sum 변수를 캡쳐
}
print(sum)

Function literals with receiver

함수 리터럴이란 이름 없는 함수 표현 자체를 의미 (람다, 익명 함수)

val sum: Int.(Int) -> Int = { other -> plus(other) } // this.plus(other)

val sum = fun Int.(other: Int): Int = this + other // 익명 함수로 표현하면 이와 같다.
class HTML {
    fun body() { ... }
}

fun html(init: HTML.() -> Unit): HTML {
    val html = HTML()  // 리시버 객체 생성
    html.init() // 파라미터로 전달 받은 Html을 리시버로 가지는 () -> Unit 호출
    return html
}

html { // 리시버가 있는 람다 시작
    body() // html 함수의 init의 매개변수로 body 전달 (Html 클래스의 () -> Unit 타입 멤버 함수)
}