# 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()
}
}
일부만 인라인 하고 싶을 때 사용한다.
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
forEach
는 인라인 함수다.lable
을 사용해야 한다.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해야 하는 코드 블록을 만들어야 한다면 람다 대신 무명 함수를 쓸 수 있다.
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")
}