🔥 제어 흐름 변경하기
Swift에서는 continue
, break
, fallthrough
, return
, throw
와 같은 5가지 제어 흐름 전환문(control transfer statements)이 있습니다. 이 키워드들은 코드의 실행 흐름을 변경해서 한 코드에서 다른 코드로 제어를 이동시킬 때 사용됩니다.
continue
continue
는 루프 안에서 현재 iteration을 끝내고 다음 iteration으로 넘어가게 해주는 키워드입니다.
예를 들어, 아래 코드는 문자열에서 모음과 공백을 제거하고 퍼즐 문구를 만들어냅니다:
let puzzleInput = "great minds think alike" var puzzleOutput = "" let charactersToRemove: [Character] = ["a", "e", "i", "o", "u", " "] for character in puzzleInput { // 제거할 문자가 포함되어 있으면 if charactersToRemove.contains(character) { // 현재 iteration을 건너뛰고 계속 진행합니다 continue } // 제거할 문자가 아니면 출력 문자열에 추가합니다 puzzleOutput.append(character) } print(puzzleOutput) // "grtmndsthnklk"
swift
루프 내에서 모음이나 공백을 만나면 continue
가 호출되어 해당 iteration이 즉시 종료되고 다음 iteration으로 건너뜁니다.
break
break
는 control flow statement의 실행을 즉시 종료하는 키워드입니다. switch
나 루프 문에서 실행을 조기에 종료하고 싶을 때 사용할 수 있습니다.
루프문에서의 break
루프문 내에서 break
를 사용하면 루프의 실행이 즉시 종료되고 }
다음의 코드로 제어가 이동합니다. 현재 iteration의 나머지 코드는 실행되지 않고, 이후의 iteration도 시작되지 않습니다.
Switch문에서의 break
switch
문 내에서 break
를 사용하면 switch
문의 실행이 즉시 종료되고 }
다음의 코드로 제어가 이동합니다.
이 기능은 switch
문에서 하나 이상의 case를 매치하고 무시하는 데 사용할 수 있습니다. Swift의 switch
문은 빈 case를 허용하지 않기 때문에, 의도를 명시적으로 표현하기 위해 무시하려는 case에 break
를 작성해야 할 때가 있습니다. 무시할 case의 본문 전체에 break
를 작성하면 됩니다.
아래는 Character
값을 switch하여 4개 언어 중 하나의 숫자 기호를 나타내는지 확인하는 예제입니다:
let numberSymbol: Character = "三" // 숫자 3의 중국어 기호 var possibleIntegerValue: Int? switch numberSymbol { case "1", "١", "一", "๑": possibleIntegerValue = 1 case "2", "٢", "二", "๒": possibleIntegerValue = 2 case "3", "٣", "三", "๓": possibleIntegerValue = 3 case "4", "٤", "四", "๔": possibleIntegerValue = 4 default: // 매치되는 case가 없으면 그냥 무시합니다 break } if let integerValue = possibleIntegerValue { print("The integer value of \(numberSymbol) is \(integerValue).") } else { print("An integer value couldn't be found for \(numberSymbol).") } // "The integer value of 三 is 3."를 출력합니다.
swift
switch
문에서 숫자 1부터 4까지의 라틴어, 아랍어, 중국어, 태국어 기호에 대해 확인합니다. 매치되는 case가 있으면 possibleIntegerValue
라는 Int?
변수에 해당 정수값을 설정합니다.
switch
문 실행이 끝나면 optional binding을 사용해서 값이 설정되었는지 확인합니다. possibleIntegerValue
는 optional 타입이므로 초기값이 nil
이고, optional binding은 switch
문의 첫 4개 case 중 하나에 의해 실제 값이 설정된 경우에만 성공합니다.
모든 가능한 Character
값을 나열하는 것은 현실적이지 않으므로, default
case에서 매치되지 않는 문자를 처리합니다. 이 default
case는 아무런 동작도 수행할 필요가 없으므로 break
문 하나로 본문을 작성했습니다. default
case가 매치되면 break
문에 의해 switch
문이 즉시 종료되고, if let
문 다음부터 코드 실행이 계속됩니다.
fallthrough
Swift에서 switch
문은 첫 번째로 매치된 case가 완료되는 즉시 전체 실행이 완료됩니다. 이는 각 case의 끝에서 다음 case로 fall through되지 않는다는 뜻입니다. 반면 C에서는 fallthrough를 막기 위해 모든 switch
case의 끝에 명시적인 break
문을 삽입해야 합니다. 기본적인 fallthrough 동작을 피함으로써 Swift의 switch
문은 C에 비해 훨씬 간결하고 예측 가능하며, 실수로 여러 switch
case를 실행하는 일이 없습니다.
C 스타일의 fallthrough 동작이 필요하다면 case별로 fallthrough
키워드를 사용해서 옵트인(opt-in)할 수 있습니다. 아래 예제는 fallthrough
를 사용해서 숫자에 대한 텍스트 설명을 만듭니다:
let integerToDescribe = 5 var description = "The number \(integerToDescribe) is" switch integerToDescribe { case 2, 3, 5, 7, 11, 13, 17, 19: description += " a prime number, and also" fallthrough default: description += " an integer." } print(description) // "The number 5 is a prime number, and also an integer."를 출력합니다.
swift
이 예제에서는 description
이라는 새 String
변수를 선언하고 초기값을 할당합니다. 그런 다음 switch
문을 사용해서 integerToDescribe
의 값을 검토합니다. integerToDescribe
의 값이 소수 목록에 있으면 숫자가 소수라는 텍스트를 description
끝에 추가합니다. 그런 다음 fallthrough
키워드를 사용해서 default
case로 "떨어집니다". default
case는 추가 텍스트를 description
끝에 덧붙이고 switch
문이 완료됩니다.
integerToDescribe
의 값이 알려진 소수 목록에 없으면 첫 번째 switch
case에 전혀 매치되지 않습니다. 다른 특정 case가 없으므로 integerToDescribe
는 default
case에 매치됩니다.
switch
문 실행이 끝나면 print(_:separator:terminator:)
함수를 사용해서 숫자에 대한 설명을 출력합니다. 이 예제에서는 숫자 5
가 소수로 올바르게 식별되었습니다.
레이블이 붙은 문
Swift에서는 루프와 조건문을 다른 루프와 조건문 안에 중첩해서 복잡한 제어 흐름 구조를 만들 수 있습니다. 그러나 루프와 조건문 모두 break
문을 사용해서 실행을 조기에 종료할 수 있습니다. 따라서 때로는 break
문으로 어떤 루프나 조건문을 종료할지 명시적으로 표현하는 것이 유용합니다. 마찬가지로 여러 개의 중첩된 루프가 있다면 continue
문으로 어떤 루프에 영향을 줄지 명시적으로 표현하는 것도 유용할 수 있습니다.
이를 위해 statement label
을 사용해서 루프문이나 조건문을 표시할 수 있습니다. 조건문에서는 break
문과 함께 statement label을 사용해서 레이블된 문의 실행을 종료할 수 있습니다. 루프문에서는 break
나 continue
문과 함께 statement label을 사용해서 레이블된 문의 실행을 종료하거나 계속할 수 있습니다.
labeled statement는 statement 도입부 키워드와 같은 줄에 레이블을 배치하고 콜론을 붙여서 표시합니다. 다음은 while
루프에 대한 구문 예제이지만, 모든 루프와 switch
문에 대해서도 동일한 원리가 적용됩니다:
<#label name#>: while <#condition#> { <#statements#> }
text
다음 예제는 이 장 앞부분에서 본 Snakes and Ladders
게임의 수정 버전에 대해 레이블이 붙은 while
루프와 함께 break
와 continue
문을 사용합니다. 이번에는 게임에 추가 규칙이 있습니다:
- 이기려면 정확히 25번 칸에 도착해야 합니다.
특정 주사위 굴림이 25번 칸을 넘어서게 한다면 정확히 25번 칸에 도착하는 데 필요한 숫자가 나올 때까지 다시 굴려야 합니다.
finalSquare
, board
, square
, diceRoll
의 값은 이전과 동일한 방식으로 초기화됩니다.
let finalSquare = 25 var board = [Int](repeating: 0, count: finalSquare + 1) board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02 board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08 var square = 0 var diceRoll = 0
swift
이 버전의 게임은 while
루프와 switch
문을 사용해서 게임 로직을 구현합니다. while
루프에는 game루프
라는 statement label이 붙어 있어서 Snakes and Ladders 게임의 메인 게임 루프임을 나타냅니다.
while
루프의 조건은 while square != finalSquare
로, 정확히 25번 칸에 도착해야 한다는 점을 반영합니다.
game루프: while square != finalSquare { diceRoll += 1 if diceRoll == 7 { diceRoll = 1 } switch square + diceRoll { case finalSquare: // 주사위 굴림으로 마지막 칸에 도착하므로 게임이 끝납니다 break game루프 case let newSquare where newSquare > finalSquare: // 주사위 굴림으로 마지막 칸을 넘어가므로 다시 굴립니다 continue game루프 default: // 유효한 이동이므로 효과를 확인합니다 square += diceRoll square += board[square] } } print("Game over!")
swift
주사위는 각 루프의 시작 부분에서 굴려집니다. 플레이어를 즉시 이동시키는 대신 루프는 switch
문을 사용해서 이동 결과를 고려하고 이동이 허용되는지 판단합니다:
- 주사위 굴림으로 플레이어가 마지막 칸으로 이동하면 게임이 끝납니다.
break game루프
문은 제어를while
루프 바깥의 첫 번째 코드 줄로 이동시켜 게임을 끝냅니다. - 주사위 굴림으로 플레이어가 마지막 칸을 넘어가면 이동이 유효하지 않고 플레이어는 다시 굴려야 합니다.
continue game루프
문은 현재while
루프의 iteration을 끝내고 루프의 다음 iteration을 시작합니다. - 다른 모든 경우에는 주사위 굴림이 유효한 이동입니다. 플레이어는
diceRoll
칸만큼 앞으로 이동하고, 게임 로직은 뱀과 사다리가 있는지 확인합니다. 그런 다음 루프가 끝나고 제어는while
조건으로 돌아가서 다른 턴이 필요한지 결정합니다.
switch
문이 실행을 마치면 print(_:separator:terminator:)
함수를 사용해서 "Game over!"를 출력하고 게임이 끝납니다.
정리해 보면:
continue
는 루프의 현재 iteration을 건너뛰고 다음 iteration으로 넘어가게 해줍니다.break
는switch
나 루프문의 실행을 즉시 종료시킵니다.- 루프문에서는 현재 iteration의 나머지 코드를 실행하지 않고 루프 바깥의 코드로 제어를 이동시킵니다.
switch
문에서는switch
문 실행을 즉시 종료하고switch
바깥의 코드로 제어를 이동시킵니다. 이를 이용해 특정 case를 무시할 수 있습니다.
fallthrough
는 C 스타일의 case 사이 fall through 동작을 구현할 때 사용합니다.- statement label을 사용하면 중첩된 루프나 조건문에서
break
나continue
로 어떤 statement를 제어할지 명시할 수 있습니다.