# 8 고차 함수:파라미터와 반환 값으로 람다 사용

#### 고차 함수란

다른 함수를 인자로 받거나 함수를 반환하는 함수다. `filter`, `with`, `map` 등등 는 술어 함수를 인자로 받으므로 고차함수다. 특징:

1. 코드를 더 간결하게 다듬고 코드 중복을 없애고 더 나은 추상화를 제공
2. 람다를 사용함에 따라 발생할 수 있는 성능 부가 비용을 없앰
3. 람다 안에서 더 유연하게 흐름을 제어할 수 있다(인라인 함수)

#### 함수 타입

- 타입 추론으로 인해 변수 타입을 지정하지 않아도 람다를 변수에 대입할 수 있다.
    - 널이 될 수 있는 타입 가능
    - 변수 타입을 지정하지 않아도 람다를 변수에 대입 가능

```kotlin
val sum: (Int, Int) -> Int = { x, y -> x + y }
val action: () -> Unit = { println(42) }

var canReturnNull: (Int, Int) -> Int? = { x, y -> null }
// 함수 타입 전체가 널이 될 수 있는 타입
var funOrNull: ((Int, Int) -> Int)? = null

인자로 받는 함수 호출

fun twoAndThree(operation: (Int, Int) -> Int) {
    val result = operation(2, 3)
    println("The result is $result")
}

자바에서 코틀린 함수 타입 사용

디폴트 값

fun foo(callback: (() -> Unit)?) {
    //...
    if (callback != null) {
        callback()
    }
}

인라인 함수

인라인 함수를 컴파일할 때 컴파일러는 그 함수의 본문과 그 함수에게 전달된 람다의 본문을 컴파일한 바이트코드를 모든 함수 호출 지점에 삽입해준다. 이렇게 만들어지는 바이트코드는 함다를 활용한 인라인 함수 코드를 풀어서 직접 쓴 경우와 비교할 때 아무 부가 비용이 들지 않는다.


inline fun <T> synchronized(lock: Lock, action: () -> T): T {
    lock.lock()
    try {
        action()
    } finally {
        lock.unlock()
    }
}

noinline

일부만 인라인 하고 싶을 때 사용한다.

inline fun foo(inlined: () -> Unit, noinline notInlined: () -> Unit) { ... }

함수를 함수에서 반환

함수가 함수를 반환할 필요가 있는 경우보다는 함수가 함수를 인자로 받아야 할 필요가 있는 경우 함수를 반환하는 함수도 유용하다.

고차 함수 안에서 흐름 제어

인라인 함수에서는 람다 안에 있는 return문에 바깥쪽 함수를 반환시키는 넌로컬 return을 사용할 수 있다.

fun foo() {
    listOf(1, 2, 3, 4, 5).forEach {
        if (it == 3) return // non-local return directly to the caller of foo()
        print(it)
    }
    println("this point is unreachable")
}

fun main() {
    foo()
}
//12

람다로부터 반환:레이블을 사용한 return

fun foo() {
    listOf(1, 2, 3, 4, 5).forEach lit@{
        if (it == 3) return@lit // local return to the caller of the lambda - the forEach loop
        print(it)
    }
    print(" done with explicit label")
}

fun main() {
    foo()
}
fun foo() {
    listOf(1, 2, 3, 4, 5).forEach {
        if (it == 3) return@forEach // local return to the caller of the lambda - the forEach loop
        print(it)
    }
    print(" done with implicit label")
}

fun main() {
    foo()
}

무명 함수 기본적 로컬 return

무명 함수는 람다 식을 대신할 수 있으며 return 식을 처리하는 규칙이 일반 람다 식과는 다르다. 본문 여러 곳에서 return해야 하는 코드 블록을 만들어야 한다면 람다 대신 무명 함수를 쓸 수 있다.

fun foo() {
    listOf(1, 2, 3, 4, 5).forEach(fun(value: Int) {
        if (value == 3) return  // local return to the caller of the anonymous function - the forEach loop
        print(value)
    })
    print(" done with anonymous function")
}