The Swift Programming Language Documents를 참고해서 정리했습니다.
여러 가지 생각들이 버무러져 있습니다.
contents
️ Control Flow
Swift는 다양한 Control Flow를 제공합니다.
for-in, while과 같은 반복문, 특정 조건에 따른 분기문, guard문, switch문, 그리고 실행 흐름 중간에 다른 지점으로 보내주는 break, continue 등을 제공해줍니다.
제공해주는 Control Flow를 사용해서 코드의 흐름을 원하는대로 제어할 수 있습니다.
️ Control Transfer Statement
Control Transfer Statement는 코드가 실행되는 순서에 영향을 줍니다.
Swift는 총 5개의 Control Transfer Statement를 제공합니다.
•
continue
•
break
•
fallthrough
•
return
•
throw
continue
continue는 루프에서 하던걸 멈추고 다음 iteration의 시작부터 다시 시작하라는 의미를 가집니다.
즉, 루프를 떠나진 않지만 현재 진행하던건 마무리가 되었고 다음 iteration을 진행하겠다는거죠.
예를 들어볼게요.
10개의 숫자가 들어 있는 배열에서 짝수만을 분리해서 출력하고 싶습니다. 이런 경우에 continue를 사용해서 홀수가 결과 배열에 들어가지 않도록 할 수 있습니다.
let numbers: [Int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
var results: [Int] = []
for num in numbers {
if num % 2 != 0 { continue }
results.append(num)
}
print(results)
/*
[2, 4, 6, 8, 10]
*/
Swift
복사
홀수라면 다음 코드를 진행하지 않고 continue를 통해서 다음 iteration으로 넘어가는걸 볼 수 있습니다.
num에 들어온 숫자가 3이라면 if문으로 들어와서 continue가 실행되고 바로 4로 넘어가는거죠. 결국, 결과 배열에는 짝수만 들어가게 됩니다.
break
break는 switch문이나 루프문을 즉시 종료시킵니다.
따라서, switch문이나 루프문 진행 중에 일찍 해당 코드 블럭을 종료시키고 싶은 경우에 사용하면 됩니다.
•
루프
루프 내부에 break를 작성하게 되면 루프 실행이 즉시 종료되고 더이상 루프를 실행할 수 없게 됩니다. 계속 루프 내부를 유지하면서 다음 iteration으로 넘어가기만 하는 continue와는 차이가 있습니다.
•
switch
루프와 동일하게 switch도 즉시 실행이 종료됩니다.
하지만, switch에서는 흔하게 break를 사용합니다. switch가 case 내부 코드 블럭이 비어있는 것을 허용하지 않기 때문입니다. 만약, 특정 case에 어떠한 코드도 실행하고 싶지 않은 경우에 해당 코드 블럭을 비워놓는 것이 아니라 break를 작성해서 해당 case를 즉시 종료시킵니다.
지금 emoji 라는 변수에 들어간 이모지가 뭘 나타내는지 확인하는 switch문을 작성했다고 해보겠습니다.
let emoji = "🌻"
var emojiToText: String?
switch emoji {
case "🐶", "🐱", "🐭", "🐹":
emojiToText = "동물"
case "🦋", "🐝", "🪲":
emojiToText = "곤충"
case "🐬", "🐳", "🦭":
emojiToText = "해양 동물"
case "🌸", "💐", "🌹", "🌻":
emojiToText = "꽃"
default:
break
}
if let emojiToText {
print("그 이모지는 \(emojiToText)을(를) 나타내요.")
}
Swift
복사
모든 case에 충족하지 않는 이모지가 들어온다면 default 케이스로 들어가게 됩니다. 하지만, default 케이스에 들어간 이모지가 어떤 것을 나타내는지 우리는 모르기 때문에 아무런 코드도 작성하고 싶지 않네요.
따라서, break를 사용해서 해당 케이스를 무시했습니다.
fallthrough
이전에 [Swift] Control Flow - Conditional Statements 포스트에서 switch문에 대해서 작성했었습니다. 그 때, Swift에서 switch문은 다른 언어와는 다르게 현재 케이스를 지나서 다음 케이스로 넘어가지 않는다는 걸 배웠습니다.
그렇다면, 다른 언어들같이 다음 케이스로 넘어가게끔 하고 싶다면 어떻게 해야 할까요?
그런 기능을 할 수 있게끔 해주는 것이 바로 fallthrough입니다. fallthrough를 사용하면 다음 케이스를 실행하게 됩니다.
하지만, 다음 케이스의 조건을 따로 체크하지 않기 때문에 이 점을 유의해서 사용해야 합니다.
조건을 만족하지 않더라도 fallthrough가 적혀있는 케이스 블록의 다음 케이스라면 무조건 실행됩니다.
let number = 2
switch number {
case let num where num % 2 == 0:
print("\(num)은 짝수입니다.")
fallthrough
default:
print("감사합니다.")
}
/*
2은 짝수입니다.
감사합니다.
*/
Swift
복사
️ Labeled Statements
이전에 알아본 루프나 switch문을 사용해서 우리는 다양한 제어 흐름을 만들어 낼 수 있습니다.
단일문으로 사용하지 않고 루프와 switch문을 중첩하여 더 복잡한 제어 흐름 구조를 생성할 수 있습니다.
이러한 복잡한 구조에서 발생할 수 있는 문제가 있다면, 과연 어떤 부분에 대한 break 혹은 continue인지가 모호해질 수가 있다는 겁니다.
이 문제를 해결할 수 있는 방법이 바로 Labeled Statement 입니다.
Labeled Statement는 break 혹은 continue할 루프나 조건문에 대해 명시적으로 나타내는 방식입니다.
어떻게 사용하는지 보기 위해서 프로그램을 하나 만들어볼게요.
해당 프로그램은 다트판 프로그램입니다. 다트를 던질 때마다 초기 점수인 50점에서 꽂힌 다트 영역의 점수가 빠집니다. 즉, 13점 영역에 다트를 맞추면 37점으로 점수가 내려갑니다. 점수가 0이 되면 게임이 끝나고 0보다 작은 수가 되면 이전 점수에서 다시 게임을 진행해야 합니다.
일단, 초기 점수를 50점으로 설정했습니다.
var score: Int = 50
Swift
복사
그리고, 게임 코드를 작성했습니다. 하지만, 해당 코드에는 문제가 있습니다.
var score: Int = 50
while true {
var point = Int.random(in: 0...20)
switch score - point {
case 0:
break
case let newScore where newScore < 0:
continue
default:
score -= point
}
}
Swift
복사
switch문 내부에 있는 break가 루프문을 멈추는지, switch문을 멈추는지가 모호합니다.
while문을 break하길 원했지만 switch문이 break되기 때문에 무한루프를 돌게 됩니다.
따라서, labeled statement를 추가해줍니다. 그러면, 멈출 곳이 어딘지가 명확해져서 이전과 같은 문제가 발생하지 않습니다.
var score: Int = 50
gameLoop: while true {
var point = Int.random(in: 0...20)
switch score - point {
case 0:
break gameLoop
case let newScore where newScore < 0:
continue gameLoop
default:
score -= point
}
}
Swift
복사