Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

구문 #71

Open
simoniful opened this issue Nov 22, 2022 · 0 comments
Open

구문 #71

simoniful opened this issue Nov 22, 2022 · 0 comments

Comments

@simoniful
Copy link
Owner

simoniful commented Nov 22, 2022

스위프트에는, 세 종류의 구문이 있는데
단순문, 컴파일러 제어문, 제어 흐름문으로 이뤄져있다
단순문이 가장 흔하며 표현식이나 선언으로 구성되고,
컴파일러 제어문은 프로그램이 컴파일러의 동작을 바꾸는 걸 허용하며
조건부 컴파일 블럭 및 라인 제어문을 포함한다

제어 흐름문은 프로그램 안의 실행 흐름을 제어하는데 사용된다
스위프트에는 반복문과 조건문 및 제어 전달문을 포함한 여러가지 타입의 제어 흐름문이 있다
반복문은 코드 블럭의 반복 실행을 허용하고,
조건문은 특정 코드 블럭이 특정 조건을 만날 때만 실행하게 하며,
제어 전달문은 코드 실행 순서를 부분적으로 바꾸는 방법을 제공한다

또한, 스위프트는 scope를 도입하여 에러를 잡아서 처리하는 do 문과,
현재 scope의 탈출 직전에 정리 작업을 실행하는 defer 문도 제공한다

세미콜론(;)은 어떤 구문 뒤에도 있을 수 있는데
이를 써서 똑같은 줄에 있는 여러 개의 구문을 구분한다

캡쳐 2022-11-24 오후 4 17 41

반복문

반복문은, 반복문이 정한 조건에 따라, 코드 블럭을 반복하여 실행하도록 한다
스위프트에는 세 개의 반복문이 있다
for-in 문, while 문, repeat-while 문

반복문의 제어 흐름은 break 문과 continue 문으로 바꿀 수 있으며
아래의 Break StatementContinue Statement 챕터에서 다룰 예정이다

캡쳐 2022-11-25 오후 2 16 41

1) For-In Statement(for-in 문)

for-in 문은 Sequence 프로토콜을 준수한
집합체(collection) 혹은 어떤 타입 안의 각 항목을 순회하면서 한 번씩 코드 블럭을 실행하게 한다

for-in 문의 형식은 다음과 같다

for item in collection {
statements
}

집합체(collection) 표현식의 makeIterator() 메소드를 호출하여
반복자 타입, IteratorProtocol 프로토콜을 준수하는 타입-의 값을 구한다
프로그램은 반복자의 next() 메소드를 호출함으로써 반복문 실행을 시작한다
반환 값이 nil 이 아니면, 이를 item 변수 패턴에 할당하여,
프로그램이 구문(statements)을 실행한 다음,
반복문 맨 앞에서 실행을 계속한다
그 외 경우, 프로그램이 할당이나 구문(statements) 실행을 하지 않고 for-in 문 실행을 종료한다

캡쳐 2022-11-25 오후 2 31 54

2) While 문

while 문은, 조건이 참으로 남아 있는 한, 코드 블럭을 반복 실행하도록 한다
while 문의 형식은 다음과 같다

while condition {
statements
}

while 문은 다음 처럼 실행하는데

  1. 조건 (condition)을 평가한다
    true면 실행을 2단계로 계속한다
    false면 프로그램이 while 문 실행을 종료한다
  2. 프로그램이 구문(statements)을 실행하고, 실행을 다시 1단계로 돌린다

조건(condition)값을 구문(statements) 실행 전에 평가하기 때문에,
while 문 안의 구문(statements)을 0번 이상 실행할 수 있다

조건(condition) 값은 반드시 Bool 타입 또는 Bool과 연동한 타입이어야 한다
Optional Binding 페이지에서 설명한 것처럼,
조건이 옵셔널 바인딩 선언일 수도 있다

캡쳐 2022-11-25 오후 2 59 47

3) Repeat-While 문

repeat-while 문은 조건이 참으로 남아 있는 한, 코드 블럭을 한 번 이상 실행하도록 한다
repeat-while 문의 형식은 다음과 같다

repeat {
statements
} while condition

repeat-while 문은 다음 처럼 실행하는데

  1. 프로그램이 구문(statements)을 실행하고, 2단계를 계속 실행한다
  2. 조건(condition)을 평가한다
    true면 실행을 1단계로 돌린다
    false면 프로그램이 repeat-while 문의 실행을 종료한다

조건(condition) 값을 구문(statements) 실행 후에 평가하기 때문에,
repeat-while 문 안의 구문(statements)을 적어도 한 번은 실행한다

조건(condition) 값은 반드시 Bool 타입 또는 Bool과 연동한 타입이어야 한다
Optional Binding 페이지에서 설명한 것처럼,
조건이 옵셔널 바인딩 선언일 수도 있다

캡쳐 2022-11-25 오후 3 03 53

조건문(Branch Statements)

조건문은 하나 이상의 조건 값에 따라 프로그램이 특정 코드를 실행하도록 한다
조건문에서 정한 조건 값이 프로그램을 어떻게 분기할지를
즉, 무슨 코드 블럭을 실행할지 제어한다
스위프트에는 세 개의 조건문이 있다
if 문, guard 문, switch 문

if 문 또는 switch 문의 제어 흐름은
break 문으로 바꿀 수 있으며
이는 아래 설명할 Break Statement 페이지에서 이야기 할 예정이다

캡쳐 2022-11-25 오후 3 06 12

1) If 문

if 문을 사용하면 하나 이상의 조건 평가에 기초하여 코드를 실행한다
if 문에는 기본 형식이 두 개 있다. 각각의 형식에서 열고 닫는 중괄호는 필수다
첫 번째 형식은 조건이 참일 때만 코드를 실행하게 하며 형식은 다음과 같다

if condition {
statements
}

두 번째 형식의 if 문은 else 키워드를 도입한 else 절(else clause)을 추가하며
이를 사용하여 코드 한 부분은 조건이 참일 때 실행하고
다른 부분은 동일 조건이 거짓일 때 실행한다
단 하나의 else 절만 있을 때의, if 문 형식은 다음과 같다

if condition {
statements to execute if condition is true
} else {
statements to execute if condition is false
}

if 문의 else 절에 또 다른 if 문을 담으면 하나 이상의 조건을 테스트할 수도 있다
이런 식으로 사슬처럼 이은 if 문 형식은 다음과 같다

if condition 1 {
statements to execute if condition 1 is true
} else if condition 2 {
statements to execute if condition 2 is true
} else {
statements to execute if both conditions are false
}

어떤 If 문이든 조건(condition) 값은 반드시 Bool 타입 또는 Bool과 연동한 타입이어야 한다
Optional Binding 페이지에서 설명한 것처럼,
조건이 옵셔널 바인딩 선언일 수도 있다

캡쳐 2022-11-25 오후 3 09 46

2) Guard 문

guard 문은 하나 이상의 조건과 만나지 않을 경우 프로그램 제어를 영역 밖으로 전달하는데 사용한다
guard 문의 형식은 다음과 같다

guard condition else {
statements
}

어떤 guard 문이든 조건(condition) 값은 반드시 Bool 타입 또는 Bool과 연동한 타입이어야 한다
Optional Binding 페이지에서 설명한 것처럼,
조건이 옵셔널 바인딩 선언일 수도 있다

guard 문 조건 안의 옵셔널 바인딩 선언에서
값을 할당한 어떤 상수나 변수든 guard 문을 둘러싼 나머지 영역에서 사용할 수 있다

guard 문에서 else 절은 필수이며,
반드시 Never 반환 타입의 함수를 호출하거나
아니면 다음 구문 중 하나로 프로그램 제어를 guard 문을 둘러싼 영역 밖으로 전달해야 한다

  • return
  • break
  • continue
  • throw

제어 전달문은 아래의Control Transfer Statements 페이지에서 이야기한다

Never 반환 타입인 함수에 대한 더 많은 정보는, Functions that Never Return 페이지에서 더 알 수 있다

캡쳐 2022-11-25 오후 3 13 59

3) Switch 문

switch 문은 제어 표현식 값에 따라 특정 코드 블럭을 실행하도록 한다
switch 문의 형식은 다음과 같다

switch control expression {
case pattern 1:
statements
case pattern 2 where condition:
statements
case pattern 3 where condition,
pattern 4 where condition:
statements
default:
statements
}

switch 문의 제어 표현식(control expression)을 평가한 다음
각각의 case 에서 정한 패턴과 비교한다
일치한 걸 찾으면, 프로그램이 해당 case 영역에서 나열한 구문(statements)을 실행한다
각 case 영역은 비어있을 수 없다
그 결과, 각 case 이름표 콜론(:) 뒤에 적어도 하나의 구문을 반드시 포함해야한다
일치한 case 절 본문에서 어떤 코드도 실행하지 않을 의도면 단일 break 문을 사용해야한다

코드가 분기할 수 있는 표현식 값은 매우 유연하다
예를 들어, 정수와 문자 같은 크기 값만 가지는 스칼라 타입 값과 더불어
부동-소수점 수와 문자열, 튜플, 커스텀 클래스 인스턴스 및 옵셔널을 포함한 어떤 타입 값으로도 코드를 분기할 수 있다
심지어 제어 표현식(control expression) 값을 열거체 case 값과 맞춰볼 수도 있고
특정 값 범위에 포함되는지도 검사할 수 있다
switch 문에서 이렇게 다양한 타입의 값을 사용하는 방법은,
제어 구문속의 Switch 페이지에서 확인할 수 있다

switch 문 case는 각각의 패턴 뒤에 옵션으로 where 절을 담을 수 있다
where 절(where clause)은 where 키워드와 그 뒤의 표현식으로 도입하며,
이를 써서 case 안의 패턴을 제어 표현식(control expression)과 맞춰보기 전에 추가 조건을 제공한다

where 절이 있으면, 제어 표현식(control expression) 값이 case 패턴 중 하나와 일치하면서
where 절 표현식이 true 로 평가된 경우에만
연관된 case 안의 구문(statements)을 실행한다
예를 들어, 아래 예제에선 (1, 1) 같이 동일한 두 원소를 담은 튜플인 경우에만
제어 표현식(control expression)과 case가 일치하게 된다

case let (x, y) where x == y:

위 예제에서 보인 것처럼, let 키워드로 case 안의 패턴을 상수와 연결할 수도 var 키워드로 변수와 연결할 수도 있다
그러면 해당 where 절과 case 영역 안의 코드 나머지 부분에서 이러한 상수나 변수를 참조할 수 있다
case에 담은 패턴 여러 개가 제어 표현식과 일치하면,
모든 패턴이 반드시 똑같은 상수 및 변수 연결을 담아야 하고,
연결한 각각의 변수나 상수 타입은 반드시 모든 case 패턴에서 동일해야한다

switch 문은 기본 case 절을 포함할 수 있으며, default 키워드로 도입한다
제어 표현식과 일치한 다른 case 절이 없는 경우에만 기본 case 절 안의 코드를 실행하며
switch 문은 단 하나의 기본 case 절만 포함할 수 있고 반드시 switch 문 끝에 나타나야 한다

패턴-맞춤 연산의 실제 실행 순서는 case 안의 패턴 평가 순서를 정하진 않지만
switch 문의 패턴 맞춤은 마치 소스 코드에 나타난 순서로 평가하는 것처럼 동작한다
결과적으로, 다수의 경우가 동일한 값으로 평가하는 패턴을 포함하고
따라서 제어 표현식 값과 일치할 수 있다면
소스 순서상 첫 번째로 일치한 case 안의 코드만을 프로그램이 실행된다

3-1) switch 문은 철저해야 한다(Switch Statements Must Be Exhaustive)

스위프트에서 모든 가능한 제어 표현식 타입의 값은 반드시 적어도 하나의 case 패턴과 일치해야 한다
이의 실현이 단순하지 않은 예를 들어, 제어 표현식 타입이 Int 와 같은 경우
default case 절을 포함하여 필수 조건을 만족할 수 있다

3-2) 향후 열거체 case로의 전환(Switching Over Future Enumeration Cases)

nonfrozen 열거체는
미래에 심지어 앱을 컴파일하고 출하한 후에도 새로운 열거체 case를 얻을 수 있는 특수한 종류의 열거체이다
nonfrozen 열거체로의 전환에는 부가적으로 고려할 게 있다

라이브러리 작성자가 열거체를 nonfrozen으로 표시할 땐,
새로운 열거체 case를 추가할 권리를 보유하며,
해당 열거체와 상호 작용할 코드는 반드시 재컴파일 없이 이러한 미래 case 들을 처리할 수 있어야 한다

library evolution mode로 컴파일한 코드, 표준 라이브러리 안의 코드, 애플 프레임웍을 스위프트로 덧씌운 것, C와 오브젝티브-C 코드가
nonfrozen 열거체를 선언할 수 있다
frozen 및 nonfrozen 열거체에 대한 정보는, frozen 페이지에서 확인할 수 있다

nonfrozen 열거체의 값을 전환할 땐,
열거체의 모든 case 에 해당 switch 문의 case가 이미 있더라도
항상 default case 절을 포함할 필요가 있다

@unknown 특성을 default case 절에 적용하여,
기본 사례가 향후 추가되는 열거 사례와 일치해야 함을 나타낼 수 있다

Swift는 default case가 컴파일 시점에 알려진 열거 case와 일치하면 경고를 생성한다
이 이후 경고는 라이브러리 작성자가 해당 switch 문 case가 없는 새로운 case를 열거체에 추가했다는 걸 알려준다

다음 예제는 표준 라이브러리에 있는 Mirror.AncestorRepresentation 열거체의
모든 기존의 3가지 case 들을 전환한다
추가적인 case를 미래에 추가하면, 컴파일러가 경고를 생성하여 새로운 case를 고려하도록 switch 문을 업데이트할 필요가 있다는 걸 지시한다

let representation: Mirror.AncestorRepresentation = .generated
switch representation {
case .customized:
    print("Use the nearest ancestor’s implementation.")
case .generated:
    print("Generate a default mirror for all ancestor classes.")
case .suppressed:
    print("Suppress the representation of all ancestor classes.")
@unknown default:
    print("Use a representation that was unknown when this code was compiled.")
}
// Prints "Generate a default mirror for all ancestor classes."

3-3) 실행은 암시적으로 사례를 통과하지 않는다(Execution Does Not Fall Through Cases Implicitly)

일치한 case 절 안의 코드 실행을 마치면, 프로그램은 switch 문에서 종료되어 빠져나간다
일치하지 않더라도 프로그램 실행은 다음 case 절이나 default case 절로 계속되지 중간에 “빠져 버리지(fall through)” 않는다

그렇더라도, 실행이 한 case 절에서 그 다음으로 계속되길 원한다면,
실행을 계속할 case 절 안에 단순히 fallthrough 키워드로 구성된 fallthrough 문을 명시적으로 포함하면 된다
fallthrough 문에 대한 더 많은 정보는 Fallthrough Statement 페이지에서 알 수 있다

캡쳐 2022-11-25 오후 3 48 00

라벨문

반복문이나 if 문, switch 문, 또는 do 문 앞엔 접두사로 구문 라벨(statement label)을 둘 수 있는데,
이는 라벨 이름과 그 바로 뒤의 콜론(:)으로 구성된다
밑에 있는 Break StatementContinue Statement 부분에서 논의하듯,
반복문이나 switch 문 안에서 제어 흐름을 바꿀 방법을 명시하려면, break 및 continue 문에 구문 라벨을 사용한다

라벨문의 영역은 구문 라벨 뒤의 전체 구문이다
라벨문을 중첩할 순 있지만, 각각의 구문 라벨 이름은 반드시 유일해야 한다

구문 라벨에 대한 더 많은 정보와 사용 방법 예제를 보려면,
제어 흐름 파트의 Labeled Statements 페이지 부분을 보도록 하자

캡쳐 2022-11-25 오후 3 53 08

제어 전달문

제어 전달문은 프로그램 제어를 코드 한 곳에서 다른 곳으로 무조건 전달함으로써
프로그램 코드의 실행 순서를 바꿀 수 있다
스위프트에는 다섯 개의 제어 전달문이 있다
break 문, continue 문, fallthrough 문, return 문, throw 문

캡쳐 2022-11-25 오후 4 01 08

1) Break 문

break 문은 반복문이나 if 문, 또는 switch 문의 프로그램 실행을 끝낸다
밑에서 보는 것처럼, break 문은 break 키워드로만 구성하거나,
break 키워드와 그 뒤의 구문 라벨로 구성할 수 있다

break
break label name

break 문 뒤에 구문 라벨이 있을 땐,
해당 라벨이 있는 반복문이나 if 문, 또는 switch 문의 프로그램 실행을 끝낸다

break 문 뒤에 구문 이름표가 없을 땐,
자기가 있는 switch 문이나 자기를 둘러싼 가장 안쪽 반복문의 프로그램 실행을 끝낸다
라벨이 없는 break 문을 써서 if 문을 끊어 나올 순 없다

두 경우 모두 프로그램 제어는 자신을 둘러싼 반복문 또는 switch 문 뒤의 첫 번째 코드 행으로 전송된다

break 문의 사용법에 대한 예제는
제어 흐름 파트의 BreakLabeled Statements 페이지를 참고하자

캡쳐 2022-11-25 오후 4 06 07

2) Continue 문

continue 문은 반복문의 현재 회차 프로그램 실행을 종료하지만 반복문의 실행은 멈추지 않는다
밑에 예시처럼 continue 문은 continue 키워드로만 구성하거나,
continue 키워드와 그 뒤의 구문 라벨로 구성할 수 있다

continue
continue label name

continue 문 뒤에 구문 라벨이 있을 땐,
해당 라벨이 있는 반복문의 현재 회차 프로그램 실행을 종료한다

continue 문 뒤에 구문 이름표가 없을 땐,
자기를 가장 안쪽에서 둘러싼 반복문의 프로그램 실행을 종료한다

두 경우 모두, 그런 다음 자신을 둘러싼 반복문의 조건절로 프로그램 제어를 전달한다

for 문에선 continue 문 실행 후에도 여전히 증가 표현식을 평가하는데,
반복문 본문을 실행한 후 증가 표현식을 평가하기 때문이다

continue 문의 사용법에 대한 예제는,
제어 흐름 파트에 있는
ContinueLabeled Statements 페이지를 참고하자

캡쳐 2022-11-25 오후 4 09 42

3) Fallthrough 문

fallthrough 문은 fallthrough 키워드로 구성하며 switch 문의 case 블럭 안에만 있다
fallthrough 문은 프로그램 실행을 switch 문의 한 case 절에서 그 다음 case 절로 계속하게 한다
프로그램 실행은 case 라벨 패턴이 switch 문의 제어 표현식 값과 일치하지 않더라도 그 다음 case 절로 계속된다

fallthrough 문은, case 블럭 마지막 문장만이 아니라,
switch 문 안의 어떤 곳에든 나타날 수 있지만, 최종 case 블럭에선 사용할 수 없다
값 연결 패턴을 담은 case 블럭으로 제어를 전달할 수도 없다

switch 문에서 fallthrough 문의 사용법에 대한 예제는,
제어흐름 파트의 Control Transfer Statements 페이지 부분를 참고하자

캡쳐 2022-11-25 오후 4 13 12

4) Return 문

return 문은 함수나 메소드 정의 본문 안에 작성하며
프로그램 실행을 호출한 함수나 메소드로 쪽으로 되돌려 반환한다
프로그램 실행은 함수나 메소드 호출 바로 다음 지점에서 계속된다

밑에 예시처럼 return 문은 return 키워드로만 구성하거나,
return 키워드와 그 뒤의 표현식으로 구성할 수 있다

return
return expression

return 문 뒤에 표현식이 있을 땐,
표현식 값을 호출 함수나 메소드로 반환한다
표현식 값이 함수나 메소드 선언에서 선언한 반환 타입 값과 일치하지 않으면,
호출 함수나 메소드로 반환하기 전에 표현식 값을 반환 타입으로 변환한다

Failable Initializers에서 설명한 것처럼,
실패 가능 초기자에선 return nil 이라는 특수한 형식의 return 문을 사용하여 초기화 실패를 지시할 수 있다

return 문 뒤에 표현식이 없을 땐,
값을 반환하지 않는 함수나 메소드 반환에서만
즉, 함수나 메소드 반환 타입이 Void 나 () 일 때만 사용할 수 있다

image

5) Throw 문

throw 문은 throwing 함수나 메소드 본문 안이나,
타입에 throws 키워드를 표시한 클로저 표현식 본문 안에서 발생한다

throw 문은 프로그램이 현재 영역의 실행은 끝내고
자신을 둘러싼 영역으로 에러 전파를 시작하게 한다
던진 에러는 do 문의 catch 절이 처리하기 전까지 계속 전파된다

밑에서 보는 것처럼, throw 문은 throw 키워드와 그 뒤의 표현식으로 구성된다

throw expression

표현식(expression) 값은 반드시 Error 프로토콜을 준수한 타입이어야 한다

throw 문의 사용법에 대한 예제는, 에러 핸들링 파트의 Propagating Errors Using Throwing Functions 페이지 부분을 참고하자

캡쳐 2022-11-25 오후 5 32 39

Defer 문

defer 문을 사용하면 defer 문이 있는 영역 밖으로 프로그램 제어를 전달하기 바로 직전에 코드를 실행한다
defer 문의 형식은 다음과 같다

defer {
statements
}

defer 문 안의 구문은 어떻게 프로그램 제어를 전달하던 간에 실행한다
즉, defer 문을 사용하면 file descriptors 닫기 같은 manual resource management를 수행하고
에러를 던지더라도 발생할 필요가 있는 작업을 수행할 수 있다는 의미가 된다
file descriptors는 POSIX 운영 체제에서 특정 파일에 접근하기 위한 추상적인 키를 의미한다
defer 문을 사용하면 프로그램이 열어둔 파일을 닫더라도 그 전에 특정 구문을 실행하게 할 수 있다

동일한 영역에 여러 개의 defer 문이 있으면, 작성한 순서의 역순으로 실행된다
주어진 영역의 마지막 defer 문을 첫 번째로 실행한다는 건
해당 마지막 defer 문 안의 구문이 다른 defer 문에 의해 정리될 자원을 참조할 수 있음을 의미한다

func f() {
    defer { print("First defer") }
    defer { print("Second defer") }
    print("End of function")
}

f()
// Prints "End of function"
// Prints "Second defer"
// Prints "First defer"

defer 문 안의 구문이 defer 문 밖으로 프로그램 제어를 전달할 순 없다

캡쳐 2022-11-25 오후 5 41 29

Do 문

do 문을 사용하여 새로운 scope를 도입하면,
정의한 에러 조건과 매칭할 패턴을 담은 catch 절을 하나 이상 옵셔널하게 담을 수 있다
do 문 영역에서 선언한 변수와 상수는 그 영역 안에서만 접근할 수 있다

스위프트의 do 문은 C 언어에서 코드 블럭을 구분할 때 쓰는 중괄호 ({}) 와 비슷하며
런타임에 성능 비용을 초래하지 않는다

do 문의 형식은 다음과 같다

do {
try expression
statements
} catch pattern 1 {
statements
} catch pattern 2 where condition {
statements
} catch pattern 3, pattern 4 where condition {
statements
} catch {
statements
}

어떤 do 코드 블럭의 구문이든 에러를 던지면,
프로그램 제어를 첫 번째로 에러와 일치한 패턴의 catch 절로 전달한다
일치한 절이 없으면 주위 영역으로 에러를 전파한다
최상단까지 에러를 처리하지 않으면, 런타임 에러로 프로그램 실행이 멈추게 된다

switch 문과 같이 컴파일러는 catch 절이 완전한지 추론을 시도한다
완전하다고 결정할 수 있으면 에러를 처리한다고 고려한다
그 외 경우, 자신을 담은 영역 밖으로 에러를 전파할 수 있는데,
이는 반드시 자신을 둘러싼 catch 절이 에러를 처리하거나
자신을 담은 함수를 throws 로 선언해야 한다는 걸 의미한다

패턴이 여러 개인 catch 절은 하나라도 에러와 일치하면 에러와 일치한다
catch 절에 패턴이 여러 개면 모든 패턴이 반드시 동일한 상수 또는 변수 바인딩을 포함해야 하며,
바인딩한 각각의 변수나 상수의 타입은 반드시 모든 catch 절 패턴에서 동일한 타입이어야 한다

오류가 처리되도록 하려면 와일드카드 패턴(_)과 같이 모든 오류와 일치하는 패턴이 있는 catch 절을 사용해야한다
catch 절이 패턴을 지정하지 않으면 catch 절은 error라는 이름의 로컬 상수에 모든 오류를 일치시키고 바인딩한다
catch 절에 쓸 수 있는 패턴에 대한 더 많은 정보는,
Patterns 파트에서 더 알아보자

여러 catch 절이 있는 do 문의 사용법에 대한 예제를 보려면,
Handling Errors 페이지 부분을 보도록하자

캡쳐 2022-11-25 오후 5 55 06

컴파일러 제어문

컴파일러 제어문은 프로그램이 컴파일러 동작 부분을 바꾸도록 한다
스위프트에는 세 개의 컴파일러 제어문이 있다
조건부 컴파일 블럭, 라인 제어문, 컴파일-시간 진단문

캡쳐 2022-11-25 오후 5 56 38

1) 조건부 컴파일 블럭(Conditional Compilation Block)

조건부 컴파일 블럭은 하나 이상의 컴파일 조건 값에 따라 코드를 조건부로 컴파일하도록 한다

모든 조건부 컴파일 블럭은 #if 컴파일 지시자로 시작해서 #endif 컴파일 지시자로 끝난다
단순한 조건부 컴파일 블럭의 형식은 다음과 같다

#if compilation condition
statements
#endif

if 문 조건과는 달리 컴파일 조건(compile condition)은 컴파일 시점에 평가한다
그 결과, 컴파일 시점에 컴파일 조건(compile condition)이 true 로 평가될 때만 구문(statements)을 컴파일하고 실행한다

컴파일 조건(compile condition)은 true 및 false 불리언 글자값이나,
-D Command line flag와 사용하는 식별자,
또는 밑의 표에 나열한 어떤 플랫폼 조건이든 포함할 수 있다

image

swift()와 compiler() 플랫폼 조건에서 버전 번호는,
주요(major) 번호와, 옵션인 보조(minor) 번호, 역시 옵션인 패치(patch) 번호 등
각 버전 번호 부분을 점(.) 으로 구분하여 구성한다
반드시 비교 연산자와 버전 번호 사이에 공백이 없어야 한다

compiler() 버전은 컴파일러에 전달한 스위프트 버전 설정과는 상관없는 컴파일러 버전을 의미한다
이는 컴파일러 버전과 소스 코드 상의 스위프트 언어 버전이 다를 수 있기 때문이다
swift() 버전은 현재 컴파일하고 있는 언어의 버전이다

예를 들어, 스위프트 5 컴파일러에서 스위프트 4.2 모드로 컴파일하면,
compiler() 버전은 5 이고 swift() 버전은 4.2가 된다
이렇게 설정하면, 다음 코드는 세 개의 메시지를 모두 인쇄한다

#if compiler(>=5)
print("Compiled with the Swift 5 compiler or later")
#endif
#if swift(>=4.2)
print("Compiled in Swift 4.2 mode or later")
#endif
#if compiler(>=5) && swift(<5)
print("Compiled with the Swift 5 compiler or later in a Swift mode earlier than 5")
#endif
// Prints "Compiled with the Swift 5 compiler or later"
// Prints "Compiled in Swift 4.2 mode or later"
// Prints "Compiled with the Swift 5 compiler or later in a Swift mode earlier than 5"

canImport() 플랫폼 조건의 인수는 모든 플랫폼에 있는 건 아닐 수도 있는 모듈의 이름이다
모듈 이름은 마침표(.)를 포함할 수 있다
해당 조건은 모듈 불러오기가 가능한지 검사하는 것이지, 실제로 불러오는 건 아니다
모듈이 있으면 플랫폼 조건이 true를 반환하며, 그 외 경우, false를 반환한다

targetEnvironment() 플랫폼 조건은 특정 환경에서 코드를 컴파일할 때 true를 반환하며, 그 외 경우, false를 반환한다

arch(arm) 플랫폼 조건은 ARM 64 기기에서 true를 반환하지 않는다
arch(i386) 플랫폼 조건은 32-비트 iOS 시뮬레이터에서 코드를 컴파일할 때 true를 반환한다

컴파일 조건들을 && 와, ||, 및 ! 등의 논리 연산자와 괄호 그룹으로 조합하고 반대로 뒤집을 수 있다
이러한 연산자는 평범한 불리언 표현식 조합에 쓰이는 논리 연산자와 동일한 결합 법칙 및 우선 순위를 가진다

if 문과 비슷하게, 조건 분기를 여러 개 추가하면 서로 다른 컴파일 조건을 검사할 수 있다
#elseif 절로 어떤 개수의 추가 분기든 추가할 수 있고
#else 절로 추가적인 최종 분기를 추가할 수도 있다
여러 분기를 담은 조건부 컴파일 블럭의 형식은 다음과 같다

#if compilation condition 1
statements to compile if compilation condition 1 is true
#elseif compilation condition 2
statements to compile if compilation condition 2 is true
#else
statements to compile if both compilation conditions are false
#endif

조건부 컴파일 블럭 본문 안의 각 구문은 컴파일하지 않더라도 해석한다
하지만, 컴파일 조건에 swift() 나 compiler() 플랫폼 조건이 포함되면 예외인데
플랫폼 조건에서 정한 것과 일치한 언어 또는 컴파일러 버전인 경우에만 해석한다
이런 예외를 통해 더 오래된 컴파일러가 새 버전 스위프트에서 도입한 구문을 해석하려 하지 않도록 보장하게 된다

조건부 컴파일 블럭에서 명시적 멤버 표현식을 포장할 수 있는 방법에 대한 정보는,
Explicit Member Expression 페이지를 통해 알 수 있다

캡쳐 2022-11-25 오후 6 11 48

1) 라인 제어문(Line Control Statement)

라인 제어문을 사용하여 컴파일 중인 소스 코드의 줄 번호 및 파일 이름과 다를 수 있는 줄 번호 및 파일 이름을 지정한다
스위프트가 진단(diagnostic) 및 디버깅(debugging) 목적으로 사용할 소스 코드 위치를 바꾸기 위해 라인 제어문을 사용한다

라인 제어문의 형식은 다음과 같다

#sourceLocation(file: file path, line: line number)
#sourceLocation()

첫 번째 형식의 라인 제어문은
라인 제어문의 다음 코드 줄에서 시작하는
#line, #file, #fileID, #filePath 글자 표현식 값을 바꾼다

라인 번호(line number)는 #line 값을 바꾸는 0 보다 큰 어떤 정수 글자값이다
파일 경로(file path)는 #file, #fileID, #filePath 값을 바꾸는 문자열 글자값이다
지정한 문자열이 #filePath 값이 되고,
문자열의 마지막 경로 구성요소는 #fileID 값으로 사용된다
#file, #fileID, #filePath에 대한 정보는,
Literal Expression 페이지에서 더 알 수 있다

두 번째 형식의 라인 제어문인 #sourceLocation()은
소스 코드 위치를 기본 라인 번호 및 파일 경로로 재설정한다

캡쳐 2022-11-25 오후 6 17 38

2) 컴파일 시점 진단문(Compile-Time Diagnostic Statement)

컴파일 시점 진단문은 컴파일 중에 컴파일러가 에러(error) 나 경고(warning)를 내뿜도록 한다
컴파일 시점 진단문의 형식은 다음과 같다

#error("error message")
#warning("warning message")

첫 번째 형식은 에러 메시지(error message)를 Fatal Error로 내뿜고 컴파일 과정을 종결한다
두 번째 형식은 경고 메시지 (warning message)를 치명적이진 않은 경고라고 내뿜고 컴파일은 계속 진행하도록 한다
진단 메시지는 정적 문자열 글자값으로 작성한다
정적 문자열 글자값은 문자열 보간이나 이어붙이기 같은 특징을 사용할 순 없지만,
여러 줄짜리 문자열 글자값 구문을 사용할 순 있다

캡쳐 2022-11-25 오후 6 20 46

사용 가능성 조건(Availability Condition)

사용 가능성 조건(availablility condition)을
if 문, while 문, guard 문 조건에 사용하면
지정한 플랫폼 인자를 기초로 런타임에 API의 사용 가능성을 조회한다

사용 가능성 조건의 형식은 다음과 같다

if #available(platform name version, ..., *) {
statements to execute if the APIs are available
} else {
fallback statements to execute if the APIs are unavailable
}

사용 가능성 조건을 사용하면
사용하고 싶은 API 가 런타임에 사용 가능한 지에 따라 코드 블럭을 실행한다
해당 코드 블럭 안의 API 가 사용 가능한지 입증할 때 컴파일러가 사용 가능성 조건 정보를 사용하게 된다

사용 가능성 조건은 쉼표로 구분한 플랫폼 이름 및 버전 목록을 취한다
플랫폼 이름으론 iOS 와, macOS, watchOS, 및 tvOS 를 사용하고 해당하는 버전 번호를 포함한다
* 인자는 필수이며 다른 어떤 플랫폼에서든 대상이 지정한 최소 배포 대상에서
사용 가능성 조건이 보호할 코드 블럭 본문을 실행하도록 지정한다

불리언 조건과 달리, 사용 가능성 조건을 && 와 || 같은 논리 연산자로 조합할 순 없다
! 연산자로 사용 가능성 조건을 반대로 뒤집게 아닌, 다음 형식의 사용 불가능성 조건을 구성할 수 있다

if #unavailable(platform name version, ...) {
fallback statements to execute if the APIs are unavailable
} else {
statements to execute if the APIs are available
}

#unavailable 형식은 조건을 반대로 뒤집는 수월한 구문이다
사용 불가능성 조건에서 * 인자는 암시적아라 반드시 포함되면 안된다
이것의 의미는 사용 가능성 조건안의 * 인자와 동일하다

캡쳐 2022-11-25 오후 6 27 14

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant