본문 바로가기
프로그래밍/Kotlin

Kotlin - 반환 및 제어 흐름 건너뛰기 - return, continue, break

by pentode 2019. 7. 29.

이번에 볼 것은 함수 또는 람다 표현식에서 반환문(return)을 사용하는 방법과 루프의 반복을 건너뛰거나(continue) 바로 빠져 나오는(break) 방법입니다.


- return : 기본적인 사용법은 return문장을 둘러싼 가장 가까운 함수 또는 익명 함수에서 반환합니다. 반환값이 있을수도 없을수도 있습니다. 기본적인 사용법에서라고 말한것은 코틀린에서는 라벨 반환을 할 수 있습니다.

- break : 가장 가까운 둘러싼 루프를 종료합니다.

- continue : 가장 가까운 둘러싼 루프의 다음 반복을 진행합니다.


※ 참고 :  둘러싼 가장 가까운 루프, 함수, 익명함수 라고 하는 것은 함수 또는 루프가 중첩될 경우 그중에 가장 가까운 것을 의미합니다.


이 return, continue, break는 다른 표현식의 일부로 사용되어 질 수 있습니다. 아래 코드는 person.name이 null 이면 반환합니다.


val s = person.name ?: return


※ 참고 : 위에서 사용된 연산자 ?: 은 null일 경우 기본값을 주는 연산자로 앞이 null이면 ?: 뒤의 같이 사용되어집니다. 여기에 return 도 사용할 수 있습니다.


return, contiunu, break 표현식의 타입은 Nothing 타입 입니다.


※ 참고 : Nothing 타입은 특수한 타입으로 값을 가지지 않습니다. 이 이외에도 throw 같은 표현식도 Nothing 타입 입니다. Nothing 타입은 함수가 아무것도 반환하지 않는다은 의미로 직접 사용할 수 도 있습니다.



1. break와 continue 라벨


코틀린에서는 모든 표현식(expression)에 라벨을 붙일 수 있습니다. 라벨은 식별자 뒤에 @ 사인이 붙는 형태를 가집니다. 예를 들면: abc@, fooBar@이 유효한 라벨 입니다. 표현식에 라벨을 달기 위해서는 표현식의 앞에 라벨을 붙이기만 하면 됩니다.


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

    // ...

}


이제 continue 또는 break를 라벨과 함께 사용할 수 있게 되었습니다.


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

    for (j in 1..100) {

        if (...) break@loop

    }

}


라벨이 있는 break문은 break를 만나면 라벨이 붙은 루프의 바로 뒤의 실행문으로 점프합니다. continue는 라벨이 표시된 루프의 다음 반복을 실행합니다.



2. 라벨로 return


코틀린에서 함수 리터럴, 로컬 함수, 객체 표현식 및 함수는 중첩될 수 있습니다. 정규 return(일반적으로 사용하는 return)은 바깥쪽 함수로부터 반환할 수 있도록 합니다. 가장 중요한 사용예는 람다 표현식으로 부터의 반환입니다.


※ 참고 : 함수내에서 람다 함수를 사용할 때 람다 함수내에서 리턴하면 람다 함수만 빠져 나오는 것이 아니라 람다를 포함하고 있는 함수를 반환합니다. 이것이 기본 동작입니다.


※ 참고

- 함수 리터럴(function literals) : 코틀린에서는 함수 자체가 리터럴이 될 수 있습니다. 코틀린에서 함수는 일급 시민(first-class citizen)입니다. 이것은 함수가 인자로 전달되거나, 반환되거나, 변수에 할당 될 수 있다는 뜻입니다.

- 로컬 함수(local function) : 함수 내에서 정의되는 함수로 함수 안에서만 사용할 수 있습니다. 함수 안에서만 사용되는 코드를 재사용하는데 사용되어집니다.

- 객체 표현식(object expression) : object 키워드를 사용해서 어떤 객체를 상속한 익명 객체를 만드는데 사용됩니다.


fun foo() {

    listOf(1, 2, 3, 4, 5).forEach {

        if (it == 3) return // 함수 foo()를 호출한 곳으로 바로 non-local return 합니다.

        print(it)

    }

    println("이 지점에 도할 할 수 없습니다.")

}


※ 참고 : non-local reutrn은 람다에서 return문을 썻을때 람다가 아닌 그것을 포함하고 있는 함수를 반환하는 것을 말합니다. 람다에서만 반환하는 것이 아래에 나오는 local return 입니다.


return 표현식은 가장 가까운 둘러싼 함수로부터 반환합니다. 즉, foo() 함수를 빠져나갑니다.(이러한 non-local 반환은 인라인 함수로 보내어지는 람다 표현식에만 지원됩니다). 람다 표현식으로부터의 반환이 필요하다면 라벨을 붙이고 그 라벨로 반환하도록 해야 합니다.


fun foo() {

    listOf(1, 2, 3, 4, 5).forEach lit@{

        if (it == 3) return@lit // 람다를 호출한 곳으로 local return. 즉, forEach 루프로 리턴합니다.

        print(it)

    }

    print("명시적 라벨 사용으로 이곳에 도달 합니다.")

}


이제 위의 반환은 람다 표현식에서만 반환 합니다. 종종 암시적인 라벨을 사용하는 것이 더 편리합니다. 이러한 라벨은 람다를 보내는 함수와 같은 이름을 가집니다.


fun foo() {

    listOf(1, 2, 3, 4, 5).forEach {

        if (it == 3) return@forEach // 람다를 호출한 곳으로 local return. 즉, forEach 루프로 리턴합니다.

        print(it)

    }

    print("암시적 라벨 사용으로 이곳에 도달 합니다.")

}


또는, 람다 표현식을 익명 함수로 대체할 수 있습니다. 익명함수 내의 return 문은 익명함수 자신에서 반환합니다.


fun foo() {

    listOf(1, 2, 3, 4, 5).forEach(fun(value: Int) {

        if (value == 3) return  // 익명 함수를 호출한 곳으로 local return. 즉, forEach 루프로 리턴합니다.

        print(value)

    })

    print("익명함수 사용으로 이곳에 도달 합니다.")

}


이전의 세 가지 예에서 로컬 리턴의 사용은 일반 루프에서 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")

}


값을 반환할때, 파서는 라벨 있는 return을 우선합니다. 즉,


return@a 1


이것은 라벨이 붙은 표현식 (@a 1)을 반환하는 것이 아니라 라벨 @a 에 1을 반환하는것을 의미합니다.


※ 참고 : 위의 예는 라벨로 리턴시 반환값을 반환하는 방법 입니다.


출처 : https://kotlinlang.org/docs/reference/returns.html

반응형