본문 바로가기

Kotlin/Play Kotlin Example

Kotlin 공식 Examples로 공부하기 - Control Flow (When, Ranges, Expression, Statement, Loops, Iterator)

제어문(Control Flow)

  • 저는 전문 번역가도 아니고, 의역을 넘어 오역, 심지어 그냥 제가 읽고 싶은대로 읽은 내용이 있을 수 있습니다.
  • 개인 공부를 한 것을 포스트로 남기고 있으며 틀린 부분이 있으면 지적해주시면 수정하도록 하겠습니다.
  • 원문 : https://play.kotlinlang.org/byExample/02_control_flow/01_When

When

널리 사용하는 switch 문(statement) 대신에 코틀린은 조금 더 유연하고 깔끔한 when 문(construction)을 제공합니다. when 문은 statementexpression 으로 사용될 수 있습니다.

When Statement

fun main() {
    cases("Hello")
    cases(1)
    cases(0L)
    cases(MyClass())
    cases("hello")
}

fun cases(obj: Any) {                                
    when (obj) {                                // 이것이 when statement 입니다.   
        1 -> println("One")                     // obj가 1과 같은지 검사합니다.
        "Hello" -> println("Greeting")          // obj가 Hello와 같은지 검사합니다.
        is Long -> println("Long")              // obj가 Long타입인지 검사합니다.
        !is String -> println("Not a string")   // obj가 String타입이 아닌지 검사합니다.
        else -> println("Unknown")              // 디폴트(default) 상황에서는 해당 구문이 실행됩니다.(생략 가능)
    }   
}

class MyClass

모든 분기는 조건 중에 하나를 만족할 때까지 순차적으로 실행됩니다. 그렇기 때문에 가장 먼저 조건에 부합하는 분기만 실행될 것입니다.

When Expression

fun main() {
    println(whenAssign("Hello"))
    println(whenAssign(3.4))
    println(whenAssign(1))
    println(whenAssign(MyClass()))
}

fun whenAssign(obj: Any): Any {
    val result = when (obj) {      // 이것이 when expression 입니다.
        1 -> "one"                 // obj가 1과 같으면 값에 "one"이 설정됩니다.
        "Hello" -> 1               // obj가 Hello와 같으면 값에 1이 설정됩니다.
        is Long -> false           // obj가 Long타입의 인스턴스라면 값에 false가 설정됩니다.
        else -> 42                 // 앞에 있는 조건을 하나도 만족하지 못한 경우 값에 42가 설정됩니다.
    }
    return result                  
}

class MyClass

when statement와는 다르게 when expression 에서는 디폴트 분기(else)가 대부분 있어야 합니다. (컴파일러가 앞에 있는 케이스가 가능한 모든 케이스를 커버한다고 판단할 수 있는 경우를 제외하면 when expression에서는 else가 반드시 있어야합니다.)


반복문(Loops)

코틀린은 일반적으로 사용되는 모든 반복문을 지원합니다. (for , while , do-while)

for

코틀린에서 for 는 대부분의 프로그래밍 언어와 동일하게 동작합니다.

val cakes = listOf("carrot", "cheese", "chocolate")

for (cake in cakes) {                               // 리스트(cakes)에 있는 케이크를 반복합니다.
    println("Yummy, it's a $cake cake!")
}

while, do-while

코틀린에서 while , do-while 은 대부분의 프로그래밍 언어와 유사하게 동작합니다.

fun eatACake() = println("Eat a Cake")
fun bakeACake() = println("Bake a Cake")

fun main(args: Array<String>) {
    var cakesEaten = 0
    var cakesBaked = 0

    while (cakesEaten < 5) {         // condition이 true인 동안 블럭을 실행합니다.
        eatACake()
        cakesEaten ++
    }

    do {                             // 블럭을 한 번 실행하고, condition을 체크합니다.
        bakeACake()
        cakesBaked++
    } while (cakesBaked < cakesEaten)

}

Iterator

내가 만든 클래스에 iterator 연산자를 구현하여 나만의 iterator를 정의할 수 있습니다.

class Animal(val name: String)

class Zoo(val animals: List<Animal>) {

    operator fun iterator(): Iterator<Animal> {             // 1
        return animals.iterator()                           // 2
    }
}

fun main() {

    val zoo = Zoo(listOf(Animal("zebra"), Animal("lion")))

    for (animal in zoo) {                                   // 3
        println("Watch out, it's a ${animal.name}")
    }
}
  1. 클래스에 iterator를 정의합니다. 메소드 이름은 반드시 iterator 여야하고 앞에 operator 라는 키워드를 붙여야만 합니다.
  2. 다음 메소드 요구사항을 만족하는 iterator를 리턴합니다.
    • next() : Animal
    • hasNext() : Boolean
  3. zoo(iterator를 구현했음) 안에 있는 animal을 반복합니다.

iterator는 타입이나 확장함수로 선언될 수 있습니다.


Ranges

코틀린에는 범위(ranges)를 정의하기 위한 여러 방법이 있습니다.

for(i in 0..3) {             // 0 부터 3(포함)까지 1씩 증가하면서 반복
    print(i)
}
print(" ")

for(i in 2..8 step 2) {      // 2 부터 8(포함)까지 2씩 증가하면서 반복 (custom increment step)
    print(i)
}
print(" ")

for (i in 3 downTo 0) {      // 3 부터 0까지 역순으로 반복
    print(i)
}
print(" ")
// result : 0123 2468 3210

Char ranges도 지원합니다.

for (c in 'a'..'d') {        // 알파벳순으로 char 범위를 반복합니다.('d'포함)
    print(c)
}
print(" ")

for (c in 'z' downTo 's' step 2) { // char ranges도 'step'과 'downTo' 키워드를 지원합니다.
    print(c)
}
print(" ")
// result : abcd zxvt

if 문에서 range는 유용합니다.

val x = 2
if (x in 1..5) {            // 값이 범위(1 부터 5)에 있는지 검사합니다.
    print("x is in range from 1 to 5")
}
println()

if (x !in 6..10) {          // !in은 in의 반대입니다. (포함되지 않는지 검사합니다.)
    print("x is not in range from 6 to 10")
}

동등성 검사(Equality Checks)

코틀린은 구조 비교를 위해 == 연산자를 사용하고 참조 비교를 위해 === 연산자를 사용합니다.

명확하게, a == ba == null ? b == null : a.equals(b) 로 컴파일합니다.

(a가 null이면 b가 null인지에 따라 true, false리턴, a가 null이 아니면 a.equals(b)의 결과 리턴)

val authors = setOf("Shakespeare", "Hemingway", "Twain")
val writers = setOf("Twain", "Shakespeare", "Hemingway")

println(authors == writers)   // 1
println(authors === writers)  // 2
  1. true 리턴, authors.equals(writers)를 호출하기 때문이고 set 은 컬렉션에 저장된 요소의 순서를 무시하기 때문에 구조적으로 같다고 판단한다.
  2. false 리턴, authors와 writers가 다른 참조값을 갖기 때문이다.

Conditional Expression

코틀린에는 삼항연산자 condition ? then : else 가 없습니다. 대신 ifexpression 으로 사용됩니다. (statement 가 아니다.)

fun max(a: Int, b: Int) = if (a > b) a else b  //if는 expression으로 동작하고 값을 리턴합니다.

println(max(99, -42))

사설

기본적인 분기 처리고 눈으로 봤을 때 이해가 어려운 부분은 없지만 막상 사용하려고 코드를 쳐보면 어색하거나 문법이 기억이 안 나는 경험을 했습니다...

사용해버릇하면 좋을 것 같습니다.

  • 코드마니아 2020.07.28 10:40

    맞아요. 공부할때는 보면서 하니까 눈에 들어오는거 같은데, 막상 쓰려고 하면 생각이 안나죠. 아마정님 말씀대로 뭘 만들든 한번씩 코틀린 용법 사용해야겠어요.