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

Kotlin - 흐름제어(Control Flow): if, when, for, while

by pentode 2019. 7. 13.

코틀린에서 프로그램의 흐름을 제어하는 방법을 알아봅니다. 흐름제어에는 if, when, for, while이 사용되어 집니다. 다른 언어와 유사합니다.



1. if 표현식(If Expression)


코틀린에서 if는 표현식 입니다. 즉, if가 반환값을 가집니다. 그러므로 코틀린에는 삼항 연산자(조건 ? 참일때 : 거짓일때)가 없습니다. 왜냐하면 보통 if가 삼항연산자의 역할을 잘 수행하기 때문입니다.


// 전통적인 사용법

var max = a

if (a < b) max = b


// else를 가지는 사용법

var max: Int

if (a > b) {

    max = a

} else {

    max = b

}


// 표현식으로의 사용법

val max = if (a > b) a else b


if 표현식의 브랜치는 여러문장을 가지는 블록으로 구성될 수 있습니다. 이 경우 블록의 마지막 표현식이 반환값이 됩니다.


val max = if (a > b) {

    print("Choose a")

    a

} else {

    print("Choose b")

    b

}


if를 문장보다 표현식으로 사용하는 경우(예로 값을 반환하거나 변수에 할당하는 경우), 표현식은 else를 반드시 가져야 합니다.



2. When 표현식(When Expression)


when은 C와 유사한 언어의 스위치 연산자를 대체합니다. 아래와 같은 간단한 사용형식을 가집니다.


when (x) {

    1 -> print("x == 1")

    2 -> print("x == 2")

    else -> { // Note the block

        print("x is neither 1 nor 2")

    }

}


when은 인수에 대응하는 모든 분기를 분기 조건이 충족될때까지 순차적으로 맞춰봅니다. when은 표현식이나 문장으로 사용될 수 있습니다. 표현식으로 사용되면 만족하는 분기의 값이 전체 표현식의 값이 됩니다. 문장으로 사용되면 개별분기의 값은 무시 됩니다(if와 같이 각 분기에 블록을 사용할 수 있으며, 그 값은 블록의 마지막 표현식의 값입니다).


else 분기는 만족되어지는 다른 분기 조건이 없을때 평가되어 집니다. when이 표현식으로 사용되면, 컴파일러가 모든 가능한 경우가 분기 조건에 존재한다는 것을 증명할 수 없는한 else 분기는 반드시 있어야 합니다(예로 enum 클래스의 모든 엔트리가 분기에 사용된 경우 또는 sealed class의 서브타입 등이 사용된 경우).


※ 참고 : sealed class는 enum 클래스의 확장으로 서브타입 클래스를 sealed 클래스를 선언할때 지정하게 됩니다. enum과의 차이라면 enum이 하나의 인스턴스만을 가지지만 sealed클래스늘 여러개의 인스턴스를 가질 수 있다는 것입니다. 위에서 when에 인자가 sealed 클래스이고 sealed 클래스의 서브타입이 모두 분기 조건에 사용되었다면 else가 필요 없게 됩니다.


많은 경우가 같은 방식으로 처리된다면, 분기 조건은 콤마(,)로 결합되어질 수 있습니다.


when (x) {

    0, 1 -> print("x == 0 or x == 1")

    else -> print("otherwise")

}


분기조건에 상수 뿐만아니라 임의의 표현식을 사용할 수 있습니다.


when (x) {

    parseInt(s) -> print("s encodes x")

    else -> print("s does not encode x")

}


또한 분기조건으로 범위 또는 컬렉션에 포함되는지, 되지 않는지의 체크를 사용할 수 있습니다(in 또는 !in).


when (x) {

    in 1..10 -> print("x is in the range")

    in validNumbers -> print("x is valid")

    !in 10..20 -> print("x is outside the range")

    else -> print("none of the above")

}


또다른 가능한것은 특정 타입의 값이 있는지 확인하는 것입니다(is 또는 !is). 스마트 캐스트로 인해 별도의 점검없이 타입의 메소드나 속성에 접근할 수 있다는 점에 유의해야 합니다.


※ 참고 : 스마트 캐스트는 코틀린에서 is 또는 !is로 객체의 유형을 검사한 후 처리 블록 내에서 자동으로 캐스팅이 되는것을 말합니다. 자동으로 캐스팅이 되므로 명시적인 형변환이 필요없습니다.


fun hasPrefix(x: Any) = when(x) {

    is String -> x.startsWith("prefix")

    else -> false

}


when은 또한 if-else if 체인을 대체할 수 있습니다. 인수가 주어지지 않는다면 분기 조건은 단순히 불리언 표현일 뿐이며, 분기 조건이 참일 경우에만 분기가 실행됩니다.


when {

    x.isOdd() -> print("x is odd")

    x.isEven() -> print("x is even")

    else -> print("x is funny")

}


코틀린 1.3 이후부터 다음과 같은 구문을 사용해서 when의 subject를 변수로 캡쳐할 수 있습니다.


fun Request.getBody() =

    when (val response = executeRequest()) {

        is Success -> response.body

        is HttpError -> throw HttpException(response.status)

    }


when의 subject에 도입된 변수의 범위는 when의 바디내로 제한됩니다.



3. for 루프(For Loops)


for루프는 이터레이터를 제공하는 모든것을 반복합니다. 이것은 C#언어에서의 foreach 루프와 동등합니다. 구문은 다음과 같습니다.


for (item in collection) print(item)


바디는 블록으로 감쌀수 있습니다.


for (item: Int in ints) {

    // ...

}


앞에서 언급되었듯이 for루프는 이터레이터를 제공하는 모든것을 반복합니다.


- 멤버 함수 또는 확장 함수 iterator()를 가지며, 그 반환 타입은

- 멤버 함수 또는 확장 함수 next()를 가지고, 또한

- 멤버 함수 또는 확장 함수 hasNext()를 가지며, hasNext()의 반환값은 불리언 타입입니다.


이 세 가지 함수는 모두 operator로 표시해야 합니다.


※ 참고 : 코틀린에서 연산사 오버로딩을 위해서 함수 정의시 함수 선언 앞에 operator 키워드를 붙이게 됩니다. 위의 설명을 그것을 말하고 있습니다.


숫자 범위를 반복하고 싶으면 범위 표현을 사용합니다.


for (i in 1..3) {

    println(i)

}

for (i in 6 downTo 0 step 2) {

    println(i)

}


범위 또는 배열을 반복하는 for 루프는 iterator 객체를 생성하지 않고, 인덱스를 기반으로한 루프로 컴파일 됩니다.


배열이나 리스트를 인덱스를 통해서 반복하기를 원한다면, 아래와 같이 사용할 수 있습니다.


for (i in array.indices) {

    println(array[i])

}


또는 withIndex 라이브러리 함수를 사용할 수 있습니다. 이 방법은 인덱스과 값을 동시에 사용할 수 있습니다.


for ((index, value) in array.withIndex()) {

    println("the element at $index is $value")

}



4. while 루프(While Loops)


while과 do..while은 다른 언어들과 같이 동작합니다. while은 인자가 참이면 반복하고, do..while은 먼저 한번 실행 후 인자가 참이면 반복 합니다.


while (x > 0) {

    x--

}


do {

    val y = retrieveData()

} while (y != null) // y is visible here!



5. 루프에서 break와 continue


코틀린은 루프에서 전통적인 break와 continue를 지원합니다.



출처 : https://kotlinlang.org/docs/reference/control-flow.html

반응형