본문 바로가기
개발&프로그래밍

[kotlin] Return 과 점프 표현식

by 재아군 2024. 8. 12.

Kotlin의 Return 과 점프 표현식

Kotlin에서는 프로그램의 흐름을 제어하기 위한 다양한 구조적 점프 표현식을 제공합니다. 이 가이드에서는 return, break, continue의 사용법과 레이블을 활용한 고급 기법을 살펴보겠습니다.

 

 

기본 점프 표현식 (Basic Jump Expressions)

Kotlin은 세 가지 기본적인 구조적 점프 표현식을 제공합니다:

  1. return: 기본적으로 가장 가까운 enclosing 함수나 익명 함수에서 반환합니다.
  2. break: 가장 가까운 enclosing 루프를 종료합니다.
  3. continue: 가장 가까운 enclosing 루프의 다음 단계로 진행합니다.

이 표현식들은 더 큰 표현식의 일부로 사용될 수 있습니다:

val s = person.name ?: return

이 표현식들의 타입은 Nothing 타입입니다. 이는 이 표현식들이 "정상적인" 실행 흐름을 중단한다는 것을 의미합니다.

 

 

Break와 Continue 레이블 (Break and continue labels)

Kotlin에서는 모든 표현식에 레이블을 붙일 수 있습니다. 레이블은 식별자 뒤에 @ 기호가 붙는 형태입니다 (예: abc@ 또는 fooBar@).

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

 

이제 breakcontinue를 레이블과 함께 사용할 수 있습니다:

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

레이블이 붙은 break는 해당 레이블이 붙은 루프 바로 다음 실행 지점으로 점프합니다. 레이블이 붙은 continue는 해당 루프의 다음 반복으로 진행합니다.

이 기능은 중첩된 루프에서 특정 루프를 빠져나가거나 특정 루프의 다음 반복으로 넘어가야 할 때 매우 유용합니다.

 

 

레이블을 사용한 Return (Return to labels)

Kotlin에서는 함수 리터럴, 로컬 함수, 객체 표현식을 사용하여 함수를 중첩할 수 있습니다. 한정된 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")
}

 

 

이 경우, return 표현식은 가장 가까운 enclosing 함수인 foo에서 반환합니다. 이러한 non-local 반환은 인라인 함수에 전달된 람다 표현식에서만 지원됩니다.

람다 표현식에서 반환하려면 레이블을 붙이고 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")
}

 

 

이 경우, return@lit은 람다 표현식에서만 반환합니다.

더 편리한 방법은 암시적 레이블을 사용하는 것입니다. 암시적 레이블은 람다가 전달되는 함수와 같은 이름을 가집니다:

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

 

 

또는 람다 표현식을 익명 함수로 대체할 수 있습니다. 익명 함수 내의 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")
}

 

 

이전 세 예제에서 로컬 반환의 사용은 일반 루프에서 continue를 사용하는 것과 유사합니다.

break에 대한 직접적인 동등한 표현은 없지만, 다른 중첩 람다를 추가하고 그로부터 non-locally 반환함으로써 시뮬레이션할 수 있습니다:

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

값을 반환할 때, 파서는 한정된 반환에 우선순위를 줍니다:

return@a 1

이는 "labeled expression (@a 1)를 반환"이 아니라 "레이블 @a에서 1을 반환"을 의미합니다.

 


Kotlin의 return 과 점프 표현식은 프로그램의 흐름을 세밀하게 제어할 수 있게 해줍니다. 특히 중첩된 루프나 람다 표현식에서 이러한 기능들은 매우 강력합니다. 하지만 과도한 사용은 코드의 가독성을 해칠 수 있으므로, 적절히 사용하는 것이 중요합니다.

이러한 기능들을 잘 이해하고 활용하면, 더 효율적이고 표현력 있는 Kotlin 코드를 작성할 수 있습니다. 특히 복잡한 로직을 가진 함수나 고차 함수를 다룰 때 이러한 기능들이 큰 도움이 될 것입니다.

 

 


Kotlin, 반환문, 점프표현식, 레이블, 람다표현식, 익명함수, 제어흐름, KotlinProgramming, 코틀린문법, 프로그래밍팁, 코드최적화, 함수형프로그래밍, 안드로이드개발, 백엔드개발, KotlinCoroutines

'개발&프로그래밍' 카테고리의 다른 글

[kotlin] 클래스  (0) 2024.08.12
[kotlin] Exceptions  (0) 2024.08.12
[Kotlin] 조건문과 반복문  (0) 2024.08.11
[kotlin] 타입 체크와 캐스팅  (0) 2024.08.11
[Kotlin] 숫자 타입과 연산 가이드  (4) 2024.08.10

댓글