제어 흐름

제어 흐름 (Control flow)

다른 프로그래밍 언어처럼 Kotlin도 어떤 코드 조각이 true로 평가되는지에 따라 결정을 내릴 수 있어요. 이런 코드 조각을 조건식(conditional expression)이라고 해요. Kotlin은 또한 루프(loop)를 만들고 반복할 수도 있어요.

출처: Kotlin 공식 문서

본문

조건식 (Conditional expressions)

Kotlin은 조건식을 확인하기 위해 ifwhen을 제공해요.

Note: ifwhen 중에 골라야 한다면 when을 권장해요. 왜냐하면: 코드를 더 읽기 쉽게 만들어 줘요. 분기를 하나 더 추가하기 쉬워요. 코드에서 실수가 더 적어져요.

If

  • if를 사용하려면 괄호 () 안에 조건식을 넣고, 결과가 true일 때 취할 동작을 중괄호 {} 안에 넣어요:
fun main() {
//sampleStart
    val d: Int
    val check = true

    if (check) {
        d = 1
    } else {
        d = 2
    }

    println(d)
    // 1
//sampleEnd
}

Kotlin에는 삼항 연산자(ternary operator) condition ? then : else가 없어요. 그 대신 if를 표현식(expression)으로 사용할 수 있어요. 동작마다 코드가 한 줄뿐이라면 중괄호 {}는 생략할 수 있어요:

fun main() { 
//sampleStart
    val a = 1
    val b = 2

    println(if (a > b) a else b) // Returns a value: 2
//sampleEnd
}

When

여러 분기가 있는 조건식이 있다면 when을 사용해요.

when을 사용하려면:

  • 평가할 값을 괄호 () 안에 넣어요.
  • 분기들을 중괄호 {} 안에 넣어요.
  • 각 분기에서 각 검사와, 검사가 성공했을 때 취할 동작을 구분하는 데 ->를 사용해요.

when은 문(statement)으로 쓸 수도 있고 표현식(expression)으로 쓸 수도 있어요. 문은 아무것도 반환하지 않고 대신 동작을 수행해요.

when을 문으로 사용한 예시는 다음과 같아요:

fun main() {
//sampleStart
    val obj = "Hello"

    when (obj) {
        // Checks whether obj equals to "1"
        "1" -> println("One")
        // Checks whether obj equals to "Hello"
        "Hello" -> println("Greeting")
        // Default statement
        else -> println("Unknown")     
    }
    // Greeting
//sampleEnd
}

Note: 모든 분기 조건은 그중 하나가 충족될 때까지 순서대로 확인돼요. 그래서 첫 번째로 맞는 분기만 실행돼요.

표현식은 나중에 코드에서 사용할 수 있는 값을 반환해요.

when을 표현식으로 사용한 예시는 다음과 같아요. when 표현식은 즉시 변수에 할당되고, 그 변수는 나중에 println() 함수에서 사용돼요:

fun main() {
//sampleStart    
    val obj = "Hello"    
    
    val result = when (obj) {
        // If obj equals "1", sets result to "one"
        "1" -> "One"
        // If obj equals "Hello", sets result to "Greeting"
        "Hello" -> "Greeting"
        // Sets result to "Unknown" if no previous condition is satisfied
        else -> "Unknown"
    }
    println(result)
    // Greeting
//sampleEnd
}

지금까지 본 when 예시는 둘 다 subject(주제)가 있었어요: obj죠. 하지만 when은 subject 없이도 사용할 수 있어요.

이 예시는 subject 없는 when 표현식을 사용해서 Boolean 표현식의 연결을 확인해요:

fun main() {
    val trafficLightState = "Red" // This can be "Green", "Yellow", or "Red"

    val trafficAction = when {
        trafficLightState == "Green" -> "Go"
        trafficLightState == "Yellow" -> "Slow down"
        trafficLightState == "Red" -> "Stop"
        else -> "Malfunction"
    }

    println(trafficAction)
    // Stop
}

하지만 trafficLightState를 subject로 써서 같은 코드를 작성할 수도 있어요:

fun main() {
    val trafficLightState = "Red" // This can be "Green", "Yellow", or "Red"

    val trafficAction = when (trafficLightState) {
        "Green" -> "Go"
        "Yellow" -> "Slow down"
        "Red" -> "Stop"
        else -> "Malfunction"
    }

    println(trafficAction)  
    // Stop
}

subject와 함께 when을 쓰면 코드를 더 읽기 쉽고 유지 관리하기 쉽게 만들어 줘요. when 표현식에서 subject를 사용하면 Kotlin이 가능한 모든 경우가 다뤄졌는지 확인하는 데도 도움이 돼요. 반면 subject 없이 when 표현식을 쓰면 else 분기를 직접 제공해야 해요.

조건식 연습 (Conditional expressions practice)

연습 1 (Exercise 1)

주사위 두 개를 던져 같은 숫자가 나오면 이기는 간단한 게임을 만들어 보세요. if를 사용해서 주사위가 같으면 You win :)를, 그렇지 않으면 You lose :(를 출력하세요.

Tip: 이 연습에서는 무작위 Int를 주는 Random.nextInt() 함수를 사용할 수 있도록 패키지를 import해요. 패키지 import에 대한 자세한 내용은 Packages and imports 문서를 참고하세요.

Hint: 주사위 결과를 비교하려면 동등 연산자(==)를 사용하세요.

import kotlin.random.Random

fun main() {
    val firstResult = Random.nextInt(6)
    val secondResult = Random.nextInt(6)
    // Write your code here
}
import kotlin.random.Random

fun main() {
    val firstResult = Random.nextInt(6)
    val secondResult = Random.nextInt(6)
    if (firstResult == secondResult)
        println("You win :)")
    else
        println("You lose :(")
}

연습 2 (Exercise 2)

when 표현식을 사용해서 다음 프로그램을 수정해, 게임 콘솔 버튼 이름을 입력하면 그에 대응하는 동작을 출력하도록 만드세요.

버튼 동작
A Yes
B No
X Menu
Y Nothing
기타 There is no such button
fun main() {
    val button = "A"

    println(
        // Write your code here
    )
}
fun main() {
    val button = "A"
    
    println(
        when (button) {
            "A" -> "Yes"
            "B" -> "No"
            "X" -> "Menu"
            "Y" -> "Nothing"
            else -> "There is no such button"
        }
    )
}

범위 (Ranges)

루프를 이야기하기 전에, 루프가 반복할 범위(range)를 만드는 방법을 아는 게 유용해요.

Kotlin에서 범위를 만드는 가장 흔한 방법은 .. 연산자를 사용하는 거예요. 예를 들어 1..41, 2, 3, 4와 같아요.

끝 값을 포함하지 않는 범위를 선언하려면 ..< 연산자를 사용해요. 예를 들어 1..<41, 2, 3과 같아요.

역순 범위를 선언하려면 downTo를 사용해요. 예를 들어 4 downTo 14, 3, 2, 1과 같아요.

1이 아닌 증가 폭(step)으로 증가하는 범위를 선언하려면 step과 원하는 증가 값을 사용해요. 예를 들어 1..5 step 21, 3, 5와 같아요.

Char 범위에서도 같은 작업을 할 수 있어요:

  • 'a'..'d''a', 'b', 'c', 'd'와 같아요.
  • 'z' downTo 's' step 2'z', 'x', 'v', 't'와 같아요.

루프 (Loops)

프로그래밍에서 가장 흔한 루프 구조 두 가지는 forwhile이에요. 값의 범위를 반복하며 동작을 수행하려면 for를 사용해요. 특정 조건이 충족될 때까지 동작을 계속하려면 while을 사용해요.

For

방금 배운 범위 지식을 사용해서, 1부터 5까지의 숫자를 반복하며 매번 숫자를 출력하는 for 루프를 만들 수 있어요.

반복자(iterator)와 범위를 괄호 () 안에 in 키워드와 함께 넣어요. 완료하려는 동작을 중괄호 {} 안에 추가해요:

fun main() {
//sampleStart
    for (number in 1..5) { 
        // number is the iterator and 1..5 is the range
        print(number)
    }
    // 12345
//sampleEnd
}

컬렉션도 루프로 반복할 수 있어요:

fun main() { 
//sampleStart
    val cakes = listOf("carrot", "cheese", "chocolate")

    for (cake in cakes) {
        println("Yummy, it's a $cake cake!")
    }
    // Yummy, it's a carrot cake!
    // Yummy, it's a cheese cake!
    // Yummy, it's a chocolate cake!
//sampleEnd
}

While

while은 두 가지 방식으로 사용할 수 있어요:

  • 조건식이 true인 동안 코드 블록을 실행하는 방식. (while)
  • 코드 블록을 먼저 실행한 다음 조건식을 확인하는 방식. (do-while)

첫 번째 사용 방식(while)에서:

  • while 루프를 계속하기 위한 조건식을 괄호 () 안에 선언해요.
  • 완료하려는 동작을 중괄호 {} 안에 추가해요.

Tip: 다음 예시들은 cakesEaten 변수의 값을 증가시키기 위해 증가 연산자(increment operator) ++를 사용해요.

fun main() {
//sampleStart
    var cakesEaten = 0
    while (cakesEaten < 3) {
        println("Eat a cake")
        cakesEaten++
    }
    // Eat a cake
    // Eat a cake
    // Eat a cake
//sampleEnd
}

두 번째 사용 방식(do-while)에서:

  • while 루프를 계속하기 위한 조건식을 괄호 () 안에 선언해요.
  • 완료하려는 동작을 do 키워드와 함께 중괄호 {} 안에 정의해요.
fun main() {
//sampleStart
    var cakesEaten = 0
    var cakesBaked = 0
    while (cakesEaten < 3) {
        println("Eat a cake")
        cakesEaten++
    }
    do {
        println("Bake a cake")
        cakesBaked++
    } while (cakesBaked < cakesEaten)
    // Eat a cake
    // Eat a cake
    // Eat a cake
    // Bake a cake
    // Bake a cake
    // Bake a cake
//sampleEnd
}

조건식과 루프에 대한 더 많은 정보와 예시는 Conditions and loops 문서를 참고하세요.

이제 Kotlin 제어 흐름의 기본을 알았으니, 나만의 함수를 작성하는 법을 배워 볼 차례예요.

루프 연습 (Loops practice)

연습 1 (Exercise 1)

8조각짜리 피자 한 판이 완성될 때까지 피자 조각을 세는 프로그램이 있어요. 이 프로그램을 두 가지 방식으로 리팩터링하세요:

  • while 루프를 사용해요.
  • do-while 루프를 사용해요.
fun main() {
    var pizzaSlices = 0
    // Start refactoring here
    pizzaSlices++
    println("There's only $pizzaSlices slice/s of pizza :(")
    pizzaSlices++
    println("There's only $pizzaSlices slice/s of pizza :(")
    pizzaSlices++
    println("There's only $pizzaSlices slice/s of pizza :(")
    pizzaSlices++
    println("There's only $pizzaSlices slice/s of pizza :(")
    pizzaSlices++
    println("There's only $pizzaSlices slice/s of pizza :(")
    pizzaSlices++
    println("There's only $pizzaSlices slice/s of pizza :(")
    pizzaSlices++
    println("There's only $pizzaSlices slice/s of pizza :(")
    pizzaSlices++
    // End refactoring here
    println("There are $pizzaSlices slices of pizza. Hooray! We have a whole pizza! :D")
}
fun main() {
    var pizzaSlices = 0
    while ( pizzaSlices < 7 ) {
        pizzaSlices++
        println("There's only $pizzaSlices slice/s of pizza :(")
    }
    pizzaSlices++
    println("There are $pizzaSlices slices of pizza. Hooray! We have a whole pizza! :D")
}
fun main() {
    var pizzaSlices = 0
    pizzaSlices++
    do {
        println("There's only $pizzaSlices slice/s of pizza :(")
        pizzaSlices++
    } while ( pizzaSlices < 8 )
    println("There are $pizzaSlices slices of pizza. Hooray! We have a whole pizza! :D")
}

연습 2 (Exercise 2)

Fizz buzz 게임을 시뮬레이션하는 프로그램을 작성하세요. 1부터 100까지의 숫자를 점점 증가시키며 출력하되, 3으로 나누어 떨어지는 숫자는 "fizz"라는 단어로, 5로 나누어 떨어지는 숫자는 "buzz"라는 단어로 바꿔야 해요. 3과 5 모두로 나누어 떨어지는 숫자는 "fizzbuzz"라는 단어로 바꿔야 해요.

Hint 1: for 루프로 숫자를 세고, when 표현식으로 각 단계에서 무엇을 출력할지 결정하세요.

Hint 2: 나머지 연산자(modulo operator) %를 사용해 숫자를 나눈 나머지를 얻고, 동등 연산자(==)로 나머지가 0인지 확인하세요.

fun main() {
    // Write your code here
}
fun main() {
    for (number in 1..100) {
        println(
            when {
                number % 15 == 0 -> "fizzbuzz"
                number % 3 == 0 -> "fizz"
                number % 5 == 0 -> "buzz"
                else -> "$number"
            }
        )
    }
}

연습 3 (Exercise 3)

단어 리스트가 있어요. forif를 사용해서 l 문자로 시작하는 단어만 출력하세요.

Hint: String 타입의 .startsWith() 함수를 사용하세요.

fun main() {
    val words = listOf("dinosaur", "limousine", "magazine", "language")
    // Write your code here
}
fun main() {
    val words = listOf("dinosaur", "limousine", "magazine", "language")
    for (w in words) {
        if (w.startsWith("l"))
            println(w)
    }
}