switch문switch문을 사용하면 하나의 값을 여러 가지 가능한 값과 비교할 수 있어요.
여러 개의 else-if문을 사용하는 것보다 더 간결한 코드를 작성할 수 있게 해줘요.
switch문은 switch 키워드로 시작하고, 그 뒤에 비교할 값이 와요.
그다음 case 키워드 뒤에 비교 대상이 될 값을 적어 각 경우를 정의할 수 있어요.
default 키워드는 어떤 case와도 일치하지 않을 때 기본 경우를 정의하는 데 사용해요.
else-if문과 마찬가지로, switch문은 가장 먼저 일치하는 case와 연결된 코드 블록만 실행해요.
switch value {
case 1:
print("One")
case 2:
print("Two")
default:
print("Other")
}
다음 예시를 살펴봐요:
if str == "apple" {
print("Let's bake an apple crumble")
} else if str == "lemon" {
print("Let's bake a lemon meringue pie!")
} else if str == "peach" {
print("Let's bake a peach pie!")
} else {
print("Let's buy ice cream.")
}
이 코드는 다음과 같이 다시 쓸 수 있어요:
switch str {
case "apple":
print("Let's bake an apple crumble")
case "lemon":
print("Let's bake a lemon meringue pie!")
case "peach":
print("Let's bake a peach pie!")
default:
print("Let's buy ice cream.")
}
while문while문은 특정 조건이 참인 동안 코드를 실행할 수 있게 해 주는 제어 흐름 문이에요.
Swift는 두 가지 종류의 while문을 제공해요: while문과 repeat-while문이에요.
while문은 루프 본문이 실행되기 전에 조건을 먼저 평가해요. 조건이 거짓이면 루프 본문은 아예 실행되지 않아요.
Swift의 while문은 다음과 같은 구조를 가져요:
while <#condition#> {
<#code#>
}
여기서 루프는 count가 0보다 큰 동안 실행되며, 그에 따라 숫자 2, 1과 "Liftoff!"가 출력돼요.
var count = 2
while count > 0 {
print("\(count)…")
count -= 1
}
print("Liftoff!")
// prints:
// 2…
// 1…
// Liftoff!
repeat-while문은 while문과 비슷하지만, 루프 본문이 실행된 뒤에 조건을 평가해요.
즉, 조건이 거짓이더라도 루프 본문은 항상 적어도 한 번은 실행돼요.
Swift의 repeat-while문은 다음과 같은 구조를 가져요:
repeat {
<#code#>
} while <#condition#>
여기서는 조건이 거짓이기 때문에 루프가 한 번만 실행돼요.
repeat-while문이기 때문에 루프 본문은 조건이 평가되기 전에 한 번 실행돼요.
var count = 2
repeat {
print("\(count)…")
} while count < 0
print("Liftoff!")
Swift에는 루프의 일반적인 제어 흐름을 바꾸는 데 사용할 수 있는 문들이 있어요.
이런 것들을 제어 전달문이라고 해요.
return은 이미 봤고, 이번 개념에서는 continue, break, 레이블 같은 다른 것들을 소개해요.
이번 개념에서는 fallthrough는 다루지 않지만, Swift 책에서 읽어볼 수 있어요.
continue때로는 루프의 현재 반복에서 나머지 문을 모두 실행하지 않고, 다음 반복으로 일찍 건너뛰어야 할 때가 있어요.
이때 continue 키워드를 사용할 수 있어요.
continue가 실행되면 루프는 다음 반복을 실행할 수 있는지 확인하는 지점으로 넘어가요. 즉, while문과 repeat-while문에서는 while 부분이고, for-in문에서는 시퀀스에 다음 요소가 있는지 확인하는 부분이에요.
count = 1
while count < 6 {
count += 1
if count == 4 { continue }
print(count)
}
// prints:
// 2
// 3
// 5
breakbreak는 루프를 일찍 빠져나가는 데 사용해요.
break가 실행되면 루프는 즉시 종료되고, 프로그램은 루프 다음의 첫 번째 문부터 계속 실행해요.
for fruit in ["banana", "grapes", "apple", "strawberry", "kiwi", "lemon"] {
if !fruit.count.isMultiple(of: 2) { break }
print(fruit)
}
// prints:
// banana
// grapes
루프가 중첩되어 있을 때에는, break나 continue가 사용된 루프를 감싸는 바깥쪽 루프를 종료하거나 다시 시작하기 위해 break나 continue를 사용하고 싶을 때가 있어요.
이런 경우 레이블을 사용해 종료하거나 다시 시작할 루프를 지정할 수 있어요.
루프를 시작하는 while, repeat, for 앞에 이름과 콜론을 붙이면 루프에 레이블을 달 수 있어요.
이렇게 레이블을 사용했을 때의 효과를 보려면 다음 루프를 살펴봐요.
outerLoop: for fruit in ["banana", "grapes", "apple", "strawberry", "kiwi", "lemon"] {
print("\n--- \(fruit) ---")
for letter in fruit {
guard letter != "n" else { break outerLoop }
print(letter)
}
}
// prints:
// --- banana ---
// b
// a
최고의 믹솔로지스트로서, 사람들이 밤에 나가서 즐길 맛있는 음료를 만들어요. 그런데 코드를 조금만 작성하면 일이 훨씬 수월해질 거라고 생각했어요.
음료마다 준비하는 데 걸리는 시간이 달라요.
"beer", "soda", "water"는 각각 0.5분이 걸려요."shot"은 1.0분, "mixed drink"는 1.5분이 걸려요."fancy drink"는 2.5분이 걸려요."frozen drink"는 3.0분이 걸려요.준비해야 하는 음료를 문자열 배열로 담고 있는 drinks 인자를 받는 함수 timeToPrepare(drinks:)를 구현해요.
이 함수는 배열에 있는 모든 음료를 준비하는 데 걸리는 총 시간을 반환해야 해요.
timeToPrepare(drinks: ["beer", "frozen drink", "shot"])
// returns 4.5
근무를 시작하면 가장 먼저 해야 할 일 중 하나는, 앞으로의 근무를 위해 라임 웨지를 담은 작은 통을 가득 채워 두는 거예요. 라임은 크기에 따라 얻을 수 있는 웨지 수가 달라요. "small" 라임에서는 웨지 6개, "medium" 라임에서는 8개, "large" 라임에서는 10개를 얻을 수 있어요.
웨지가 더 필요하고 아직 손질할 라임이 남아 있는 동안에는 배열에서 첫 번째 라임을 꺼내고, 필요한 웨지 수에서 그 라임으로 얻을 수 있는 웨지 수를 빼요. 더 이상 웨지가 필요하지 않거나 라임이 다 떨어질 때까지 이 과정을 계속해요.
잘라 내야 할 웨지 수를 담은 needed와, 손질할 수 있는 라임의 크기를 문자열 배열로 담고 있는 limes 인자를 받는 함수 makeWedges(needed:limes:)를 구현해요.
이 함수는 손질한 라임의 개수를 반환해야 해요.
makeWedges(needed: 25, limes: ["small", "small", "large", "medium", "small"])
// returns 4
축하해요! 긴 근무일도 거의 끝나가고, 곧 집에 가서 새 앱을 만들 수 있어요. 하지만 다음 근무자에게 주문을 인계하고 퇴근하기 전에, 아직 처리해야 할 음료 주문이 줄줄이 남아 있어요.
근무 시간이 남아 있는 동안에는 배열의 첫 번째 주문을 만들고, 그 주문을 배열에서 제거해요.
그런 다음 timeToPrepare(drinks:) 함수를 기준으로 그 주문을 준비하는 데 걸린 시간을 남은 근무 시간에서 빼면 돼요.
근무에 남은 시간(분)과 비어 있지 않은 음료 주문 배열을 받는 함수 finishShift(minutesLeft:remainingOrders:)를 구현해요.
남은 시간은 항상 0보다 커요.
이 함수는 근무가 끝나기 전까지 처리하지 못한 주문 배열을 반환해야 해요.
finishShift(minutesLeft: 5, remainingOrders: [["beer", "frozen drink", "shot"], ["fancy drink", "soda"], ["beer", "beer", "water"], ["mixed drink", "frozen drink"]])
// returns [["beer", "beer", "water"], ["mixed drink", "frozen drink"]]
beer와 soda가 신선하게 유지되도록 하려면, 그 주문과 주문이 들어온 시간을 함께 추적해야 해요.
주문과 시간 목록이 주어지면 beer와 soda 각각의 첫 주문과 마지막 주문 시간, 총주문 수를 담은 옵셔널 튜플 한 쌍을 반환하고, 해당 음료 주문이 하나도 없으면 nil을 반환하는 함수 orderTracker(orders: [(drink: String, time: String)]) -> (beer: (first: String, last: String, total: Int)?, soda: (first: String, last: String, total: Int)?)를 구현해요.
다른 음료는 추적하지 않아도 돼요.
주문한 음료와 주문이 들어온 시간을 각각 담고 있는 튜플들의 배열을 받는 함수 orderTracker(orders:)를 구현해요.
이 함수는 beer가 주문된 첫 번째와 마지막 시간, beer 주문의 총개수, soda가 주문된 첫 번째와 마지막 시간, soda 주문의 총개수를 담은 튜플을 반환해야 해요.
반환 형식은 (beer: (first: String, last: String, total: Int)?, soda: (first: String, last: String, total: Int)?)이어야 해요.
let orders = [
(drink: "beer", time: "10:01"), (drink: "frozen drink", time: "10:02"),
(drink: "shot", time: "10:05"), (drink: "fancy drink", time: "10:06"),
(drink: "soda", time: "10:09"), (drink: "beer", time: "10:15"), (drink: "beer", time: "10:22"),
(drink: "water", time: "10:26"), (drink: "mixed drink", time: "10:28"),
(drink: "frozen drink", time: "10:33"),
]
orderTracker(orders: orders)
// returns (beer: (first "10:01", last "10:22", total 3), soda: (first "10:09", last "10:09", total 1))
Exercism에 가입하고 Swift 트랙을 개념 35개연습 문제 116개, 그리고 실제 사람의 멘토링과 함께 배우고 익혀 보세요. 모두 무료예요.