[Kotlin] 개념 정리 - Returns and jumps

2 분 소요

Kotlin : 코틀린의 기본 지식을 쌓아보자.

코틀린에는 세 개의 점프 표현식이 존재한다.

  • return: 가장 가까운 함수 또는 익명 함수에서의 반환
  • break: 가장 가까운 루프 종료
  • continue: 가장 가까운 루프 내에서 다음단계 진행

이러한 모든 표현식은 더 큰 표현식의 일부로서 사용될 수 있다.

val s = person.name ?: return

(해당 표현식의 타입은 Nothing type이다.)

Nothing type
리턴이라는 행위 자체를 하지 않음을 뜻함. 리턴 될 일이 없을 경우 or 예외를 던질 경우 사용.


Break and continue labels

코틀린 내에 모든 표현식은 label로 표시할 수 있다. 라벨은 @ 표시와 함께 식별자 형태를 갖는다.(@abc or fooBar@)

표현식에 레이블을 지정하려면, 앞에 표현식을 추가하기만 하면 된다.

loop@ for (i in 1..100) {
    // ...
}

이제, 라벨을 통해 break or continue를 사용할 수 있다.

loop@ for (i in 1..100) {
    for (j in 1..100) {
        if (...) break@loop
    }
}

라벨이 붙은 break 이후에는 즉시 표기된 라벨로 점프할 수 있게 된다.

continue의 경우 루프의 다음 반복문을 계속 진행하게 된다.


Return to labels

코틀린에서 함수들은 함수 리터럴, 지역함수, 객체 표현식를 사용하면서 중첩이 될 수 있다.

return은 바깥 함수로 반환되도록 한다.

가장 중요한 사용 유형은 람다 표현식으로부터의 반환이다.

아래 예시에서 return 표현식은 listOf(...).forEach가 아닌 가장 가까운 함수 foo에서 반환된다.

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")
}

// output: 12

이러한 non-local 반환은 오직 인라인 함수를 통과하는 람다표현식에서만 유효하다는 것에 유의하자.

람다 표현식으로부터 반환되기 위해서는 라벨링을 하고 return@xxx을 사용하라.

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")
}

// output: 1245 done with explicit label

implicit labels를 사용하는 것이 람다가 통과하는 함수명과 라벨의 이름이 일치하도록 하면 되기 때문에 종종 더 편리하게 사용할 수 있다.

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")
}

// output: 1245 done with implicit label

또 다른 대안으로, 람다 표현식을 익명 함수로 대체할 수 있다.

익명 함수에서의 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")
}

// output: 1245 done with anonymous function

이전에 예시로 들었던 것들은 모두 local return을 사용하는 것을 볼 수 있다. 이는 마치 continue를 사용하는 것과 유사하다.

반면 break와 같은 기능을 제공하지는 않는데, 아래와 같이 다른 람다식으로 감싸는 방식을 통해 우회하여 구현할 수는 있다.

fun foo() {
    run loop@{
        listOf(1, 2, 3, 4, 5).forEach {
            if (it == 3) return@loop // non-local return from the lambda passed to run
            print(it)
        }
    }
    print(" done with nested loop")
}

// output: 12 done with nested loop

값을 반환할 때 파서는 정규화된 반환에 우선 순위를 부여한다.

return@a 1

이것은 (@a 1)이라고 라벨링된 곳으로 리턴하는 것이 아닌 1@a label에 반환하라는 것을 의미한다.


참고

태그:

카테고리:

업데이트:

댓글남기기