코틀린에서 가끔씩 고차함수에서 Return 을 할 경우에 안되는 경우가 있다. 바로 아래 코드와 같은 상황일 경우에 말이다.
fun forEach(a: IntArray, action: (Int) -> Unit) {
for (n in a) action(n)
}
fun main() {
forEach(
intArrayOf(1, 2, 3, 4)) {
if (it < 2 || it > 3) return
println(it)
}
)
}
이 이유는 무엇일까?
이건 일단 람다 안에서의 return 에 대해서 생각해봐야 하는데, 일단 lambda 안에서의 return 은 가까운 함수 혹은 무언가 람다를 둘러싸고 있는 환경을 반환하려고 시도한다. 즉 위의 코드에서는 return 이라는 함수가 main() 함수를 반환하려고 시도한다는 것이다.
즉, 우리가 예상하고 있는 Return 과는 다르게 동작한다. 그래서 코틀린에서는 이를 컴파일 시켜주지 않는다. 이와 같은 사유로 코틀린에서는 Label 이라는 것을 지원한다. 즉, "어떤 함수를 끝낼 것인지 Label 을 붙여라" 라는 것이다.
묵시적 Label / 명시적 Label
Label 을 붙이는 방법에는 묵시적인 방법과 명시적인 방법이 존재한다.
명시적인 방법에는 기본적으로 Lambda 자체에도 Label 을 붙여줘야 한다. Label 은 "LabelName@" 의 형태이다.
백문이 불여일타라고, 코드를 보면 좀 더 이해가 빠를 것이다.
fun main() {
forEach(
intArrayOf(1, 2, 3, 4)) roachFunction@{
if (it < 2 || it > 3) return@roachFunction
println(it)
}
)
}
이렇게 되면 사실 익명함수가 아니라고 느껴질텐데 ㅎㅎ.. 사실 나도 그렇게 느끼지만 이런 상황에는 어쩔 수 없다고 생각한다.
위와 같은 방법을 통해서 자신이 반환하려고 하는 Context 가 어떤 Context 인지를 명시해줄 수 있다. 이를 명시적인 방법이라고 한다.
묵시적인 방법은 아래와 같이 Lamdba 에는 따로 명시를 해주지 않고, 나를 둘러 싸고 있는 특정 Label 환경을 반환할거야 라는 것을 알려준다. 명시적인 방법과 크게 차이는 나지 않는다.
fun forEach(a: IntArray, action: (Int) -> Unit) {
for (n in a) action(n)
}
fun main() {
forEach(intArrayOf(1, 2, 3, 4)) {
if (it < 2 || it > 3) return@forEach
println(it)
}
}
Inline 함수라면?
inline 함수라면 어떤 상황이 벌어질 것 같은가? inline 함수는 해당 부분에 직접 코드가 작성되는 방식으로 Label 기능 없이도 Return 이 가능하다. 정말 궁금하다면 Java 로 Decompile 된 파일을 확인하면 편하다.
fun forEach(a: IntArray, action: (Int) -> Unit) {
for (n in a) action(n)
}
inline fun forEachWithInline(a: IntArray, action: (Int) -> Unit) {
for (n in a) action(n)
}
fun main() {
forEachWithInline(intArrayOf(1, 2, 3, 4)) {
if (it < 2 || it > 3) return
println(it)
}
}
'Kotlin' 카테고리의 다른 글
Kotlin Delegation (0) | 2022.05.16 |
---|---|
Kotlin Class 내부 object 에서 Class Property 참조하는 법 (0) | 2022.05.11 |
Kotlin DSL (0) | 2022.03.28 |
Kotlin 의 확장함수가 좋은 이유 (0) | 2022.03.18 |
Ko-Test Framework 사용해보기 (0) | 2022.01.21 |