표현식 (Expressions)

Swift 에서 접두사 표현식 (prefix expressions), 이진 표현식 (binary expressions), 기본 표현식 (primary expressions), 그리고 접미사 표현식 (postfix expressions) 의 네가지 표현식이 있습니다. 표현식을 수행하면 값을 반환하거나 에러가 발생하거나 둘다 발생합니다.

접두사 그리고 이진 표현식은 더 작은 표현식에 연산자를 적용할 수 있습니다. 기본 표현식은 개념적으로 가장 간단한 표현식이며 값을 접근하는 방법을 제공합니다. 접두사와 이진 표현식과 같이 접미사 표현식은 함수 호출과 멤버 접근과 같이 접미사를 사용하여 더 복잡한 표현식을 작성할 수 있습니다. 표현식의 각 종류는 아래 섹션에서 자세하게 설명 합니다.

GRAMMAR OF AN EXPRESSION expression → try-operator opt_{opt} prefix-expression binary-expressions opt_{opt} expression-list → expression | expression , expression-list

접두사 표현식 (Prefix Expressions)

접두사 표현식 (Prefix expressions) 는 옵셔널 접두사 연산자 (prefix operator) 와 표현식을 결합합니다. 접두사 연산자는 그 뒤에 오는 표현식 인 하나의 인수를 가집니다.

이 연산자의 동작에 대한 자세한 설명은 기본 연산자 (Basic Operators)고급 연산자 (Advanced Operators) 를 참고 바랍니다.

Swift 표준 라이브러리에 의해 제공되는 연산자의 자세한 설명은 연산자 선언 (Operator Declarations) 를 참고 바랍니다.

GRAMMAR OF A PREFIX EXPRESSION prefix-expression → prefix-operator opt_{opt} postfix-expression prefix-expression → in-out-expression

In-Out 표현식 (In-Out Expression)

in-out 표현식 (in-out expression) 은 in-out 인수로 함수 호출 표현식에 전달되는 변수를 표시합니다.

in-out 파라미터에 대한 설명과 예제는 In-Out 파라미터 (In-Out Parameters) 를 참고 바랍니다.

in-out 표현식은 포인터 타입에 대한 암시적 변환 (Implicit Conversion to a Pointer Type) 에서 설명한 대로 포인터가 필요한 컨텍스트에서 비포인터 인수 (non-pointer argument) 를 제공할 때도 사용됩니다.

GRAMMAR OF AN IN-OUT EXPRESSION in-out-expression → & identifier

Try 연산자 (Try Operator)

try 표현식 (try expression) 은 에러를 던질 수 있게 try 연산자 다음에 표현식으로 구성됩니다. 형식은 다음과 같습니다:

옵셔널 try 표현식 (optional-try expression) 은 에러를 던질 수 있게 try? 연산자 다음에 표현식으로 구성됩니다. 형식은 다음과 같습니다:

표현식 이 에러를 던지지 않는다면 옵셔널 try 표현식의 값은 표현식 의 값을 포함하는 옵셔널입니다. 그렇지 않으면 옵셔널 try 표현식의 값은 nil 입니다.

강제 try 표현식 (forced-try expression) 은 에러를 던질 수 있게 try! 연산자 다음에 표현식으로 구성됩니다. 형식은 다음과 같습니다:

표현식 이 에러를 던지면 런타임 에러가 발생합니다.

이진 연산자의 왼쪽 표현식에 try, try?, 또는 try! 로 표시되면 해당 연산자는 이진 표현식 전체에 적용됩니다. 즉, 괄호를 사용하여 명시적으로 연산자의 적용 범위를 명시할 수 있습니다.

sum = try someThrowingFunction() + anotherThrowingFunction() // try applies to both function calls
sum = try (someThrowingFunction() + anotherThrowingFunction()) // try applies to both function calls
sum = (try someThrowingFunction()) + anotherThrowingFunction() // Error: try applies only to the first function call

이항 연산자가 할당 연산자 이거나 try 표현식이 괄호로 묶여있지 않으면 try 표현식은 이항 연산자의 오른쪽에 나타날 수 없습니다.

더 자세한 정보와 try, try?, 그리고 try! 사용법에 대한 예제는 에러 처리 (Error Handling) 을 참고 바랍니다.

GRAMMAR OF A TRY EXPRESSION try-operator → try | try ? | try !

이진 표현식 (Binary Expressions)

이진 표현식 (Binary expressions) 은 좌항과 우항 인수를 가지는 표현식과 중위 이항 연산자 (infix binary operator) 를 결합합니다. 형식은 다음과 같습니다:

이 연산자의 동작에 대한 자세한 설명은 기본 연산자 (Basic Operators)고급 연산자 (Advanced Operators) 를 참고 바랍니다.

Swift 표준 라이브러리에 의해 제공되는 연산자에 대한 자세한 내용은 연산자 선언 (Operator Declarations) 를 참고 바랍니다.

NOTE 구문 분석 시 이항 연산자로 구성된 표현식은 단순 목록으로 표현됩니다. 이 목록은 연산자 우선순위를 적용하여 트리로 변환됩니다. 예를 들어 표현식 2 + 3 * 5 는 처음에는 5개의 항목 2, +, 3, *, 그리고 5 의 단순 목록으로 이해됩니다. 이 프로세스는 트리 (2 + (3 * 5)) 로 변환합니다.

GRAMMAR OF A BINARY EXPRESSION binary-expression → binary-operator prefix-expression binary-expression → assignment-operator try-operator opt_{opt} prefix-expression binary-expression → conditional-operator try-operator opt_{opt} prefix-expression binary-expression → type-casting-operator binary-expressions → binary-expression binary-expressions opt_{opt}

할당 연산자 (Assignment Operator)

할당 연산자 (assignment operator) 는 주어진 표현식에 대해 새로운 값을 설정합니다. 다음의 형식을 가집니다:

표현식 의 값은 평가한 에 의해 얻어진 값으로 설정됩니다. 표현식 이 튜플이면 은 동일한 수의 요소의 튜플이어야 합니다. (중첩된 튜플도 가능합니다.) 의 각 부분에서 표현식 의 해당 부분으로 할당이 수행됩니다. 예를 들어:

(a, _, (b, c)) = ("test", 9.45, (12, 3))
// a is "test", b is 12, c is 3, and 9.45 is ignored

할당 연산자는 모든 값을 반환하지 않습니다.

GRAMMAR OF AN ASSIGNMENT OPERATOR assignment-operator → =

삼항 조건 연산자 (Ternary Conditional Operator)

삼항 조건 연산자 (ternary conditional operator) 는 조건의 값을 기반으로 주어진 두 개의 값 중 하나로 나타냅니다. 다음의 형식을 가집니다:

조건true 이면 조건부 연산자는 첫번째 표현식을 평가하고 해당 값을 반환합니다. 그렇지 않으면 두번째 표현식을 평가하고 그것의 값을 반환합니다. 사용하지 않은 표현식은 평가되지 않습니다.

삼항 조건 연산자 사용에 대한 예제는 삼항 조건 연산자 (Ternary Conditional Operator) 를 참고 바랍니다.

GRAMMAR OF A CONDITIONAL OPERATOR conditional-operator → ? expression :

타입 캐스팅 연산자 (Type-Casting Operators)

is 연산자, as 연산자, as? 연산자, 그리고 as! 연산자 인 4개의 타입 캐스팅 연산자 (type-casting operators) 가 있습니다.

다음의 형식을 가지고 있습니다:

is 연산자는 표현식 이 지정된 타입 으로 캐스팅 될 수 있는지 런타임 시에 확인합니다. 표현식 이 지정된 타입 으로 캐스팅 될 수 있으면 true 를 반환하고 그렇지 않으면 false 를 반환합니다.

as 연산자는 업캐스팅 (upcasting) 또는 브릿징 (bridging) 과 같이 캐스트가 항상 성공하는 것으로 컴파일 시 알려진 경우에 캐스팅을 수행합니다. 업캐스팅 (Upcasting) 을 사용하면 중간 변수를 사용하지 않고 표현식을 해당 타입의 상위 타입 인스턴스로 사용할 수 있습니다. 다음 접근은 동일합니다:

func f(_ any: Any) { print("Function for Any") }
func f(_ int: Int) { print("Function for Int") }
let x = 10
f(x)
// Prints "Function for Int"
let y: Any = x
f(y)
// Prints "Function for Any"
f(x as Any)
// Prints "Function for Any"

브릿징 (Bridging) 을 사용하면 새로운 인스턴스를 생성할 필요없이 NSString 과 같은 해당 Foundation 타입으로 String 과 같은 Swift 표준 라이브러리 타입의 표현식으로 사용할 수 있습니다. 브릿징에 대한 자세한 설명은 Foundation 타입 동작 (Working with Foundation Types) 를 참고 바랍니다.

as? 연산자는 지정한 타입 으로 표현식 의 조건부 캐스팅을 수행합니다. as? 연산자는 지정한 타입 의 옵셔널로 반환합니다. 런타임에 캐스팅이 성공하면 표현식 의 값은 옵셔널로 래핑되고 반환됩니다; 그렇지 않으면 반환된 값은 nil 입니다. 지정된 타입 으로 캐스팅이 실패하거나 성공이 보장되면 컴파일 시 에러가 발생합니다.

as! 연산자는 지정한 타입 으로 표현식 의 강제 캐스팅을 수행합니다. as! 연산자는 옵셔널 타입이 아닌 지정한 타입 의 값을 반환합니다. 캐스팅이 실패하면 런타임 에러가 발생합니다. x as! T 의 동작은 (x as? T)! 의 동작과 동일합니다.

타입 캐스팅에 대한 자세한 내용과 타입 캐스팅 연산자 사용에 대한 예제는 타입 캐스팅 (Type Casting) 을 참고 바랍니다.

GRAMMAR OF A TYPE-CASTING OPERATOR type-casting-operator → is type type-casting-operator → as type type-casting-operator → as ? type type-casting-operator → as ! type

기본 표현식 (Primary Expressions)

기본 표현식 (Primary expressions) 은 표현식의 가장 기본입니다. 표현식 자체로 사용될 수 있으며 접두사 표현식, 이진 표현식, 그리고 접미사 표현식을 만들기 위해 다른 토큰과 결합될 수 있습니다.

GRAMMAR OF A PRIMARY EXPRESSION primary-expression → identifier generic-argument-clause opt_{opt} primary-expression → literal-expression primary-expression → self-expression primary-expression → superclass-expression primary-expression → closure-expression primary-expression → parenthesized-expression primary-expression → tuple-expression primary-expression → implicit-member-expression primary-expression → wildcard-expression primary-expression → key-path-expression primary-expression → selector-expression primary-expression → key-path-string-expression

리터럴 표현식 (Literal Expression)

리터럴 표현식 (literal expression) 은 일반 리터럴 (문자열 또는 숫자 등), 배열 또는 딕셔너리 리터럴, 플레이그라운드 리터럴 또는 다음 특수 리터럴 중 하나로 구성됩니다:

Literal

Type

Value

#file

String

파일이 표시되는 파일의 경로입니다.

#fileID

String

파일과 모듈을 나타내는 이름입니다.

#filePath

String

파일이 표시되는 파일의 경로입니다.

#line

Int

숫자로 나타내는 라인수 입니다.

#column

Int

숫자로 시작하는 열 번호 입니다.

#function

String

선언의 이름입니다.

#dsohandle

UnsafeRawPointer

표시되는 위치에서 사용되는 동적 공유 객체 (dynamic shared object) (DSO) 처리입니다.

#file 의 문자열 값은 이전 #filePath 동작에서 새로운 #fileID 동작으로 변경 가능하도록 언어 버전에 따라 다릅니다. 현재 #file#filePath 와 동일한 값을 가집니다. Swift 의 향후 버전에서는 #file#fileID 와 동일한 값을 가질 것입니다. 향후 동작을 채택하려면 #file#fileID 또는 #filePath 로 적절하게 바꾸십시오.

#fileID 표현식의 문자열 값은 모듈 (module)/파일 (file) 의 형식을 가지며 파일 (file) 은 표현식이 나타내는 파일의 이름이고 모듈 (module) 은 이 파일이 속한 모듈의 이름을 나타냅니다. #filePath 표현식의 문자열 값은 표현식이 나타내는 파일의 전체 파일시스템 경로입니다. 이 두 값은 라인 제어 구문 (Line Control Statement) 에서 설명한대로 #sourceLocation 에 의해 변경될 수 있습니다. #fileID 는 #filePath 와 달리 소스 파일의 전체 경로를 포함하지 않으므로 개인정보보호를 강화하고 컴파일 된 바이너리의 크기를 더 줄입니다. 테스트, 빌드 스크립트, 또는 다른 프로그램의 일부가 되는 코드에 #filePath 사용은 피해야 합니다.

NOTE #fileID 표현식을 분석하려면 모듈 이름을 첫 번째 슬래시 (/) 앞의 텍스트로 읽고 파일 이름을 마지막 슬래시 이후 문자열로 읽습니다. 문자열은 MyModule/some/disambiguation/MyFile.swift 와 같이 여러개의 슬래시가 포함될 수 있습니다.

함수 내에서 #function 의 값은 해당 함수의 이름이고 메서드 내에서 해당 메서드의 이름이고 프로퍼티 getter 또는 setter 내에서 해당 프로퍼티의 이름이고 init 또는 subscript 와 같은 툭수 멤버 내에서 해당 키워드의 이름이고 파일의 최상위 수준에서는 현재 모듈의 이름입니다.

함수 또는 메서드 파라미터의 기본값으로 사용될 때 특수 리터럴의 값은 기본값 표현식은 호출될 때 결정됩니다.

func logFunctionName(string: String = #function) {
print(string)
}
func myFunction() {
logFunctionName() // Prints "myFunction()".
}

배열 리터럴 (array literal) 은 순서가 있는 값의 콜렉션입니다. 형식은 아래와 같습니다:

배열의 마지막 표현식은 옵셔널 콤마가 따라올 수 있습니다. 배열 리터럴의 값은 T 는 표현식 내의 타입인 타입 [T] 를 가집니다. 여러 타입의 표현식이 있는 경우 T 는 가장 가까운 공통 상위 타입 (supertype) 입니다. 빈 배열 리터럴은 빈 대괄호 쌍을 사용하여 작성하고 지정된 타입의 빈 배열을 생성하는데 사용될 수 있습니다.

var emptyArray: [Double] = []

딕셔너리 리터럴 (dictionary literal) 은 순서가 없는 키-값 쌍의 콜렉션입니다. 형식은 아래와 같습니다:

딕셔너리에 마지막 표현식은 옵셔널 콤마가 따라올 수 있습니다. 딕셔너리 리터럴의 값은 Key 는 키 표현식의 타입이고 Value 는 값 표현식의 타입인 타입 [Key: Value] 를 가집니다. 여러 타입의 표현식이 있는 경우 KeyValue 는 해당 값에 대해 가장 가까운 공통 상위 타입입니다. 빈 딕셔너리 리터럴은 빈 배열 리터럴과 구분하기 위해 대괄호 쌍내에 콜론 ([:]) 을 작성합니다. 지정한 키와 값 타입으로 빈 딕셔너리 리터럴을 생성하기 위해 빈 딕셔너리 리터럴을 사용할 수 있습니다.

var emptyDictionary: [String: Double] = [:]

플레이그라운드 리터럴 (playground literal) 은 프로그램 편집기 내에서 색상, 파일, 또는 이미지의 상호 표현을 생성하기 위해 Xcode 에 의해 사용됩니다. Xcode 의 외부 플레인 텍스트에서 플레이그라운드 리터럴은 특수 리터럴 구문을 사용하여 표현됩니다.

Xcode 에서 플레이그라운드 리터럴 사용에 대한 정보는 Xcode 도움에 색상, 파일, 또는 이미지 리터럴 추가하기 (Add a color, file, or image literal) 을 참고 바랍니다.

GRAMMAR OF A LITERAL EXPRESSION literal-expression → literal literal-expression → array-literal | dictionary-literal | playground-literal literal-expression → #file | #fileID | #filePath literal-expression → #line | #column | #function | #dsohandle array-literal → [ array-literal-items opt_{opt} ] array-literal-items → array-literal-item , opt_{opt} | array-literal-item , array-literal-items array-literal-item → expression dictionary-literal → [ dictionary-literal-items ] | [ : ] dictionary-literal-items → dictionary-literal-item , opt_{opt} | dictionary-literal-item , dictionary-literal-items dictionary-literal-item → expression : expression playground-literal → #colorLiteral ( red : expression , green : expression , blue :expression , alpha : expression ) playground-literal → #fileLiteral ( resourceName : expression ) playground-literal → #imageLiteral ( resourceName : expression )

Self 표현식 (Self Expression)

self 표현식은 현재 타입 또는 해당 타입의 인스턴스에 대한 명시적 참조입니다. 형식은 다음과 같습니다:

초기화 구문, 서브 스크립트, 또는 인스턴스 메서드에서 self 는 해당 타입의 현재 인스턴스를 참조합니다. 타입 메서드에서 self 는 현재 타입을 참조합니다.

self 표현식은 멤버에 접근할 때 범위를 지정하는데 사용되고 함수 파라미터와 같이 범위에 같은 이름의 다른 변수가 있을 때 명확성을 제공합니다. 예를 들어:

class SomeClass {
var greeting: String
init(greeting: String) {
self.greeting = greeting
}
}

값 타입의 변경가능 메서드 (mutating method) 에서 해당 값 타입의 새 인스턴스를 self 에 할당할 수 있습니다. 예를 들어:

struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
self = Point(x: x + deltaX, y: y + deltaY)
}
}

GRAMMAR OF A SELF EXPRESSION self-expression → self | self-method-expression | self-subscript-expression | self-initializer-expression self-method-expression → self . identifier self-subscript-expression → self [ function-call-argument-list ] self-initializer-expression → self . init

상위클래스 표현식 (Superclass Expression)

상위클래스 표현식 (superclass expression) 을 사용하면 클래스가 상위클래스와 상호작용 할 수 있습니다. 다음 형식 중 하나가 있습니다:

첫번째 형식은 상위클래스의 멤버에 접근하기 위해 사용됩니다. 두번째 형식은 상위클래스의 서브 스크립트 구현에 접근하기 위해 사용됩니다. 세번째 형식은 상위클래스의 초기화 구문에 접근하기 위해 사용됩니다.

하위클래스는 멤버, 서브 스크립팅 그리고 초기화 구문에서 상위클래스 표현식을 사용하여 상위클래스의 구현을 사용할 수 있습니다.

GRAMMAR OF A SUPERCLASS EXPRESSION superclass-expression → superclass-method-expression | superclass-subscript-expression | superclass-initializer-expression superclass-method-expression → super . identifier superclass-subscript-expression → super [ function-call-argument-list ] superclass-initializer-expression → super . init

클로저 표현식 (Closure Expression)

클로저 표현식 (closure expression) 은 다른 프로그래밍 언어에서 람다 (lambda) 또는 익명 함수 (anonymous function) 이라고도 알고 있는 클로저를 생성합니다. 함수 선언과 같이 클로저는 구문을 포함하고 둘러싸인 범위에서 상수와 변수를 캡처합니다. 형식은 다음과 같습니다:

파라미터 (parameters)함수 선언 (Function Declaration) 에서 설명 했듯이 함수 선언에서 파라미터 형식과 동일합니다.

클로저를 보다 간결하게 작성할 수 있는 몇가지 특별한 형식이 있습니다:

  • 클로저는 파라미터의 타입, 반환 타입 또는 둘 다 생략할 수 있습니다. 파라미터 이름과 타입 모두 생략하는 경우 구문 전에 in 키워드도 생략합니다. 생략한 타입을 유추할 수 없을 때 컴파일 시 에러가 발생합니다.

  • 클로저는 파라미터 이름을 생략할 수 있습니다. 파라미터는 암시적으로 $ 다음에 위치가 붙어 이름이 붙여집니다: $0, $1, $2, 등.

  • 단일 표현식으로만 구성된 클로저는 해당 포현식의 값을 반환하는 것으로 이해됩니다. 이 표현식의 내용은 주변 표현식에 대한 타입 추론을 수행할 때도 고려됩니다.

다음의 클로저 표현식은 동일합니다:

myFunction { (x: Int, y: Int) -> Int in
return x + y
}
myFunction { x, y in
return x + y
}
myFunction { return $0 + $1 }
myFunction { $0 + $1 }

함수에 인수로 클로저를 전달하는 것에 대한 정보는 함수 호출 표현식 (Function Call Expression) 을 참고 바랍니다.

클로저 표현식은 함수 호출의 일부로 클로저를 즉시 사용할 때와 같이 변수나 상수에 저장하지 않고 사용될 수 있습니다. 위 코드에서 myFunction 에 전달된 클로저 표현식은 이러한 종류의 즉각적인 사용의 예제입니다. 결과적으로 클로저 표현식은 이스케이프 (escaping) 인지 비이스케이프 (nonescaping) 인지 여부는 주변의 컨텍스트에 의해 결정됩니다. 클로저 표현식은 즉시 호출되거나 비이스케이프 함수 인수로 전달되면 비이스케이프 입니다. 그렇지 않으면 클로저 표현식은 이스케이프 입니다.

이스케이프 클로저에 대한 자세한 내용은 이스케이프 클로저 (Escaping Closures) 를 참고 바랍니다.

캡처 목록 (Capture Lists)

기본적으로 클로저 표현식은 해당 값의 강한 참조를 사용하여 주변 범위에서 상수와 변수를 캡처합니다. 캡처 목록 (capture list) 를 사용하여 클로저에서 값이 캡쳐되는 방법을 명시적으로 제어할 수 있습니다

캡처 목록은 파라미터의 목록 전에 대괄호로 둘러싸여 콤마로 구분하여 작성됩니다. 캡처 목록을 사용하면 파라미터 이름, 파라미터 타입, 그리고 반환 타입을 생략하더라도 in 키워드를 사용해야 합니다.

캡처 목록의 항목은 클로저가 생성될 때 초기화 됩니다. 캡처 목록의 각 항목에 대해 상수는 주변 범위에서 이름이 같은 상수 또는 변수의 값으로 초기화 됩니다. 예를 들어 아래 코드에서 a 는 캡처 목록에 포함되지만 b 는 포함되지 않으므로 다른 동작을 보여줍니다.

var a = 0
var b = 0
let closure = { [a] in
print(a, b)
}
a = 10
b = 10
closure()
// Prints "0 10"

주변 범위에서 변수와 클로저의 범위에서 상수로 a 라는 이름으로 두가지가 있지만 b 는 변수로 하나만 존재합니다. 내부 범위의 a 는 클로저가 생성될 때 외부 범위에서 a 의 값으로 초기화 되지만 해당 값은 특별한 방법으로 연결되지 않습니다. 이것은 외부 범위의 a 의 값이 변경되더라도 내부 범위의 a 의 값은 영향을 받지 않고 클로저 내에 a 가 변경되도 클로저 외부의 a 의 값은 영향을 받지 않습니다. 반대로 외부 범위에 b 는 하나의 변수로만 있으므로 클로저 내부 또는 외부에서 변경되면 두 위치 모두에 반영됩니다.

캡처된 변수의 타입이 의미가 있는 참조인 경우 구분이 표시되지 않습니다. 예를 들어 아래 코드에서 x 라는 이름의 두가지가 있는데 외부 범위의 변수와 내부 범위의 상수이지만 둘다 참조 의미이기 때문에 동일한 객체를 참조합니다.

class SimpleClass {
var value: Int = 0
}
var x = SimpleClass()
var y = SimpleClass()
let closure = { [x] in
print(x.value, y.value)
}
x.value = 10
y.value = 10
closure()
// Prints "10 10"

표현식의 값의 타입이 클래스라면 표현식의 값을 약한 또는 미소유 참조로 캡처하기 위해 weak 또는 unowned 로 캡처 목록에 표현식을 표시할 수 있습니다.

myFunction { print(self.title) } // implicit strong capture
myFunction { [self] in print(self.title) } // explicit strong capture
myFunction { [weak self] in print(self!.title) } // weak capture
myFunction { [unowned self] in print(self.title) } // unowned capture

캡처 목록의 명명된 값에 임의의 표현식을 바인딩 할 수도 있습니다. 표현식은 클로저가 생성될 때 평가되고 값은 지정된 강도로 캡처됩니다. 예를 들어:

// Weak capture of "self.parent" as "parent"
myFunction { [weak parent = self.parent] in print(parent!.title) }

클로저 표현식에 자세한 내용과 예제는 클로저 표현식 (Closure Expressions) 를 참고 바랍니다. 캡처 목록에 자세한 내용과 예제는 클로저에 대한 강한 참조 사이클 해결 (Resolving Strong Reference Cycles for Closures) 를 참고 바랍니다.

GRAMMAR OF A CLOSURE EXPRESSION closure-expression → { closure-signature opt_{opt} statements opt_{opt} } closure-signature → capture-list opt closure-parameter-clause throws opt_{opt} function-result opt_{opt} in closure-signature → capture-list in closure-parameter-clause → ( ) | ( closure-parameter-list ) | identifier-list closure-parameter-list → closure-parameter | closure-parameter , closure-parameter-list closure-parameter → closure-parameter-name type-annotation opt_{opt} closure-parameter → closure-parameter-name type-annotation ... closure-parameter-name → identifier capture-list → [ capture-list-items ] capture-list-items → capture-list-item | capture-list-item , capture-list-items capture-list-item → capture-specifier opt_{opt} identifier capture-list-item → capture-specifier opt_{opt} identifier = expression capture-list-item → capture-specifier opt_{opt} self-expression capture-specifier → weak | unowned | unowned(safe) | unowned(unsafe)

암시적 멤버 표현식 (Implicit Member Expression)

암시적 멤버 표현식 (implicit member expression) 은 타입 유추가 암시된 타입을 결정할 수 있는 컨텍스트에서 열거형 케이스 또는 타입 메서드와 같은 타입의 멤버에 접근하기 위한 축약된 방법입니다. 다음과 같은 형식을 가집니다:

예를 들어:

var x = MyEnumeration.someValue
x = .anotherValue

GRAMMAR OF A IMPLICIT MEMBER EXPRESSION implicit-member-expression → . identifier

괄호 안 표현식 (Parenthesized Expression)

괄호 안 표현식 (parenthesized expression) 은 표현식을 괄호로 둘러싸인 것으로 구성됩니다. 괄호를 사용하여 표현식을 명시적으로 그룹화 하여 작업의 우선순위를 지정할 수 있습니다. 그룹화 괄호는 표현식의 타입을 변경하지 않습니다—예를 들어 (1) 의 타입은 단순히 Int 입니다.

GRAMMAR OF A PARENTHESIZED EXPRESSION parenthesized-expression → ( expression )

튜플 표현식 (Tuple Expression)

튜플 표현식 (tuple expression) 은 괄호호 묶인 콤마로 구분된 표현식의 목록으로 구성됩니다. 각 표현식은 표현식 앞에 콜론 (:) 으로 구분된 식별자를 가질 수 있습니다. 형식은 다음과 같습니다:

튜플 표현식의 각 식별자는 튜플 표현식의 범위 내에서 고유해야 합니다. 중첩된 튜플 표현식에서 동일한 수준의 중첩한 식별자는 고유해야 합니다. 예를 들어 (a: 10, a: 20) 은 라벨 a 가 동일한 수준에서 두번 나타나므로 유효하지 않습니다. 그러나 (a: 10, b: (a: 1, x:2))a 가 두번 나타나도 외부 튜플과 내부 튜플에서 나타나므로 유효합니다.

튜플 표현식은 0개의 표현식을 포함하거나 2개 이상의 표현식을 포함할 수 있습니다. 괄호 안에 단일 표현식은 괄호 안 표현식 입니다.

NOTE 빈 튜플 표현식과 빈 튜플 타입 모두 Swift 에서 () 로 작성됩니다. Void() 에 대한 타입 별칭이므로 빈 튜플 타입을 작성하기위해 사용할 수 있습니다. 그러나 모든 타입 별칭과 마찬가지로 Void 는 항상 타입이므로 빈 튜플 표현식으로 작성하기 위해 사용할 수 없습니다.

GRAMMAR OF A TUPLE EXPRESSION tuple-expression → ( ) | ( tuple-element , tuple-element-list ) tuple-element-list → tuple-element | tuple-element , tuple-element-list tuple-element → expression | identifier : expression

와일드카드 표현식 (Wildcard Expression)

와일드카드 표현식 (wildcard expression) 은 할당 중에 값을 명시적으로 무시하는데 사용됩니다. 예를 들어 다음의 할당에서 10 은 x 에 할당되고 20 은 무시됩니다:

(x, _) = (10, 20)
// x is 10, and 20 is ignored

GRAMMAR OF A WILDCARD EXPRESSION wildcard-expression → _

키-경로 표현식 (Key-Path Expression)

키-경로 표현식 (key-path expression) 은 타입의 프로퍼티 또는 서브 스크립트를 참조합니다. 키-값 관찰 (key-value observing) 과 같은 동적 프로그래밍 작업 (dynamic programming tasks) 에서 키-경로 표현식을 사용합니다. 형식은 다음과 같습니다:

타입 이름 (type name)String, [Int], 또는 Set<Int> 와 같은 모든 제너릭 파라미터를 포함한 구체적 타입의 이름입니다.

경로 (path) 는 프로퍼티 이름, 서브 스크립트, 옵셔널 체이닝 표현식, 그리고 강제 언래핑한 표현식으로 구성됩니다. 이러한 각 키-경로 요소는 순서에 상관없이 필요한 만큼 여러번 반복할 수 있습니다.

컴파일 시에 키-경로 표현식은 KeyPath 클래스의 인스턴스에 의해 대체됩니다.

키 경로를 사용하여 값에 접근하려면 모든 타입에서 사용할 수 있는 subscript(keyPath:) 서브 스크립트에 키 경로를 전달해야 합니다. 예를 들어:

struct SomeStructure {
var someValue: Int
}
let s = SomeStructure(someValue: 12)
let pathToProperty = \SomeStructure.someValue
let value = s[keyPath: pathToProperty]
// value is 12

타입 이름 (type name) 은 타입 추론이 암시된 타입으로 결정할 수 있는 컨텍스트에서는 생략될 수 있습니다. 다음 코드는 \SomeClass.someProperty 대신에 \.someProperty 를 사용합니다:

class SomeClass: NSObject {
@objc dynamic var someProperty: Int
init(someProperty: Int) {
self.someProperty = someProperty
}
}
let c = SomeClass(someProperty: 10)
c.observe(\.someProperty) { object, change in
// ...
}

경로 (path) 는 식별자 키 경로 (\.self) 를 생성하기 위해 self 를 참조할 수 있습니다. 식별자 키 경로 (identity key path) 는 전체 인스턴스를 참조하므로 이를 사용하여 변수에 저장된 모든 데이터를 한번에 접근하고 변경할 수 있습니다. 예를 들어:

var compoundValue = (a: 1, b: 2)
// Equivalent to compoundValue = (a: 10, b: 20)
compoundValue[keyPath: \.self] = (a: 10, b: 20)

경로 (path) 는 프로퍼티의 값의 프로퍼티를 참조하기 위해 마침표로 구분된 여러 프로퍼티 이름이 포함될 수 있습니다. 이 코드는 OuterStructure 타입의 outer 프로퍼티의 someValue 프로퍼티를 접근하기 위해 키 경로 표현식 \OuterStructure.outer.someValue 을 사용합니다:

struct OuterStructure {
var outer: SomeStructure
init(someValue: Int) {
self.outer = SomeStructure(someValue: someValue)
}
}
let nested = OuterStructure(someValue: 24)
let nestedKeyPath = \OuterStructure.outer.someValue
let nestedValue = nested[keyPath: nestedKeyPath]
// nestedValue is 24

경로 (path) 는 서브 스크립트의 파라미터 타입이 Hashable 프로토콜을 준수하는 한 대괄호를 사용하여 서브 스크립트를 포함할 수 있습니다. 이 예제는 배열의 두번째 요소를 접근하기 위해 키 경로로 서브 스크립트를 사용합니다:

let greetings = ["hello", "hola", "bonjour", "안녕"]
let myGreeting = greetings[keyPath: \[String].[1]]
// myGreeting is 'hola'

서브 스크립트에서 사용된 값은 명명된 값 또는 리터럴 일 수 있습니다. 값은 값 의미로 사용하여 키 경로에서 캡처됩니다. 다음 코드는 키-경로 표현식과 클로저 모두에서 변수 index 를 사용하여 greetings 배역의 세번째 요소를 접근합니다. index 가 수정될 때 클로저는 새로운 인덱스를 사용하는 동안 키-경로 표현식은 여전히 세번째 요소를 참조합니다.

var index = 2
let path = \[String].[index]
let fn: ([String]) -> String = { strings in strings[index] }
print(greetings[keyPath: path])
// Prints "bonjour"
print(fn(greetings))
// Prints "bonjour"
// Setting 'index' to a new value doesn't affect 'path'
index += 1
print(greetings[keyPath: path])
// Prints "bonjour"
// Because 'fn' closes over 'index', it uses the new value
print(fn(greetings))
// Prints "안녕"

경로 (path) 는 옵셔널 체이닝과 강제 언래핑을 사용할 수 있습니다. 이 코드는 옵셔널 문자열의 프로퍼티를 접근하기 위해 키 경로에 옵셔널 체이닝을 사용합니다:

let firstGreeting: String? = greetings.first
print(firstGreeting?.count as Any)
// Prints "Optional(5)"
// Do the same thing using a key path.
let count = greetings[keyPath: \[String].first?.count]
print(count as Any)
// Prints "Optional(5)"

타입 내에 깊게 중첩된 값을 접근하기 위해 키 경로의 구성요소를 혼합하고 매치할 수 있습니다. 다음 코드는 구성요소를 결합한 키-경로 표현식을 사용하여 배열의 딕셔너리의 다른 값과 프로퍼티를 접근합니다.

let interestingNumbers = ["prime": [2, 3, 5, 7, 11, 13, 17],
"triangular": [1, 3, 6, 10, 15, 21, 28],
"hexagonal": [1, 6, 15, 28, 45, 66, 91]]
print(interestingNumbers[keyPath: \[String: [Int]].["prime"]] as Any)
// Prints "Optional([2, 3, 5, 7, 11, 13, 17])"
print(interestingNumbers[keyPath: \[String: [Int]].["prime"]![0]])
// Prints "2"
print(interestingNumbers[keyPath: \[String: [Int]].["hexagonal"]!.count])
// Prints "7"
print(interestingNumbers[keyPath: \[String: [Int]].["hexagonal"]!.count.bitWidth])
// Prints "64"

일반적으로 함수 또는 클로저를 제공하는 컨텍스트에서 키 경로 표현식을 사용할 수 있습니다. 특히, 루트 타입이 SomeType 이고 타입 (SomeType) -> Value 의 함수 또는 클로저 대신에 타입 Value 의 값을 생성하는 키 경로 표현식을 사용할 수 있습니다.

struct Task {
var description: String
var completed: Bool
}
var toDoList = [
Task(description: "Practice ping-pong.", completed: false),
Task(description: "Buy a pirate costume.", completed: true),
Task(description: "Visit Boston in the Fall.", completed: false),
]
// Both approaches below are equivalent.
let descriptions = toDoList.filter(\.completed).map(\.description)
let descriptions2 = toDoList.filter { $0.completed }.map { $0.description }

키 경로 표현식의 문제는 표현식이 평가되는 시점에만 평가됩니다. 예를 들어 키 경로 표현식에 서브 스크립트 내에 함수 호출하는 경우 함수는 키 경로가 사용될 때마다가 아니라 표현식 평가의 일부로 한번만 호출됩니다.

func makeIndex() -> Int {
print("Made an index")
return 0
}
// The line below calls makeIndex().
let taskKeyPath = \[Task][makeIndex()]
// Prints "Made an index"
// Using taskKeyPath doesn't call makeIndex() again.
let someTask = toDoList[keyPath: taskKeyPath]

Objective-C API 와 함께 상혹작용하는 코드에서 키 경로를 사용하는 것에 대한 자세한 내용은 Swift 에서 Objective-C 런타임 특성 사용 (Using Objective-C Runtime Features in Swift) 를 참고 바랍니다. 키-값 코딩과 키-값 관찰에 대한 자세한 내용은 키-값 코딩 프로그래밍 가이드 (Key-Value Coding Programming Guide)키-값 관찰 프로그래밍 가이드 (Key-Value Observing Programming Guide) 를 참고 바랍니다.

GRAMMAR OF A KEY-PATH EXPRESSION key-path-expression → \ type opt_{opt} . key-path-components key-path-components → key-path-component | key-path-component . key-path-components key-path-component → identifier key-path-postfixes opt_{opt} | key-path-postfixes key-path-postfixes → key-path-postfix key-path-postfixes opt_{opt} key-path-postfix → ? | ! | self | [ function-call-argument-list ]

선택기 표현식 (Selector Expression)

선택기 표현식 (selector expression) 을 사용하면 Objective-C 에 메서드 또는 프로퍼티의 getter 또는 setter 를 참조하는데 사용되는 선택기 (selector) 에 접근할 수 있습니다. 형식은 다음과 같습니다:

메서드 이름 (method name)프로퍼티 이름 (property name) 은 Objective-C 런타임에 사용할 수 있는 메서드 또는 프로퍼티에 대한 참조여야 합니다. 선택기 표현식의 값은 Selector 타입의 인스턴스입니다. 예를 들어:

class SomeClass: NSObject {
@objc let property: String
@objc(doSomethingWithInt:)
func doSomething(_ x: Int) { }
init(property: String) {
self.property = property
}
}
let selectorForMethod = #selector(SomeClass.doSomething(_:))
let selectorForPropertyGetter = #selector(getter: SomeClass.property)

프로퍼티의 getter 에 대한 선택기를 생성할 때 프로퍼티 이름 (property name) 은 변수 또는 상수 프로퍼티에 참조될 수 있습니다. 반대로 프로퍼티의 setter 에 대한 선택기를 생성할 때 프로퍼티 이름 (property name) 은 변수 프로퍼티에만 참조될 수 있습니다.

메서드 이름 (method name) 은 그룹화 (grouping) 을 위해 소괄호와 이름을 공유하지만 타입 서명이 다른 메서드를 명확하기 하기위해 as 연산자도 포함할 수 있습니다. 예를 들어:

extension SomeClass {
@objc(doSomethingWithString:)
func doSomething(_ x: String) { }
}
let anotherSelector = #selector(SomeClass.doSomething(_:) as (SomeClass) -> (String) -> Void)

선택기는 런타임이 아닌 컴파일 시 생성되기 때문에 컴파일러는 메서드 또는 프로퍼티가 존재하고 Objective-C 런타임에 노출되는지 확인할 수 있습니다.

NOTE 메서드 이름 (method name)프로퍼티 이름 (property name) 은 표현식이지만 절대 평가되지 않습니다.

Objective-C API 와 상호작용하는 Swift 코드에서 선택기 사용에 대한 자세한 내용은 Swift 에서 Objective-C 런타임 특성 사용 (Using Objective-C Runtime Features in Swift) 를 참고 바랍니다.

GRAMMAR OF A SELECTOR EXPRESSION selector-expression → #selector ( expression ) selector-expression → #selector ( getter: expression ) selector-expression → #selector ( setter: expression )

키-경로 문자열 표현식 (Key-Path String Expression)

키-경로 문자열 표현식 (key-path string expression) 을 사용하면 키-값 코딩 (key-value coding) 과 키-값 관찰 (key-value observing) API 에서 사용하기 위해 Objective-C 에서 프로퍼티 참조에 사용되는 문자열을 접근할 수 있습니다. 형식은 다음과 같습니다:

프로퍼티 이름 (property name) 은 Objective-C 런타임에 사용할 수 있는 프로퍼티를 참조해야 합니다. 컴파일 시에 키-경로 문자열 표현식은 문자열 리터럴에 의해 대체됩니다. 예를 들어:

class SomeClass: NSObject {
@objc var someProperty: Int
init(someProperty: Int) {
self.someProperty = someProperty
}
}
let c = SomeClass(someProperty: 12)
let keyPath = #keyPath(SomeClass.someProperty)
if let value = c.value(forKey: keyPath) {
print(value)
}
// Prints "12"

클래스 내에 키-경로 문자열 표현식을 사용할 때 클래스 이름 없이 프로퍼티 이름 만으로 해당 클래스의 프로퍼티에 참조할 수 있습니다.

extension SomeClass {
func getSomeKeyPath() -> String {
return #keyPath(someProperty)
}
}
print(keyPath == c.getSomeKeyPath())
// Prints "true"

키 경로 문자열은 런타임이 아닌 컴파일 시에 생성되기 때문에 컴파일러는 프로퍼티가 존재하고 해당 프로퍼티가 Objective-C 런타임에 노출되는지 확인할 수 있습니다.

Objective-C API 와 상호작용하는 Swift 코드에서 키 경로를 사용하는 것에 대한 자세한 내용은 Swift 에서 Objective-C 런타임 특성 사용 (Using Objective-C Runtime Features in Swift) 를 참고 바랍니다. 키-값 코딩과 키-값 관찰에 대한 자세한 내용은 키-값 코딩 프로그래밍 가이드 (Key-Value Coding Programming Guide)키-값 관찰 프로그래밍 가이드 (Key-Value Observing Programming Guide) 를 참고 바랍니다.

NOTE 프로퍼티 이름 (property name) 은 표현식이지만 절대 평가되지 않습니다.

GRAMMAR OF A KEY-PATH STRING EXPRESSION key-path-string-expression → #keyPath ( expression )

접미사 표현식 (Postfix Expressions)

접미사 표현식 (Postfix expressions) 은 접미사 연산자 (postfix operator) 또는 다른 접미사 구문 (other postfix syntax) 을 표현식에 적용하여 형성됩니다. 구문적으로 모든 기본 표현식은 접미사 표현식 입니다.

이러한 연산자의 동작에 대한 자세한 내용은 기본 연산자 (Basic Operators)고급 연산자 (Advanced Operators) 를 참고 바랍니다.

Swift 표준 라이브러리에 의해 제공되는 연산자에 대한 자세한 내용은 연산자 선언 (Operator Declarations) 을 참고 바랍니다.

GRAMMAR OF A POSTFIX EXPRESSION postfix-expression → primary-expression postfix-expression → postfix-expression postfix-operator postfix-expression → function-call-expression postfix-expression → initializer-expression postfix-expression → explicit-member-expression postfix-expression → postfix-self-expression postfix-expression → subscript-expression postfix-expression → forced-value-expression postfix-expression → optional-chaining-expression

함수 호출 표현식 (Function Call Expression)

함수 호출 표현식 (function call expression) 은 함수 이름 다음에 소괄호로 둘러싸이고 콤마로 구분된 함수의 인수의 목록으로 구성됩니다. 함수 호출 표현식 형식은 다음과 같습니다:

함수 이름 (function name) 은 값이 함수 타입인 모든 표현식이 될 수 있습니다.

함수 정의가 파라미터에 대한 이름을 포함하는 경우 함수 호출은 콜론 (:) 으로 분리하여 인수값 전에 이름을 반드시 포함해야 합니다. 이러한 종류의 함수 호출 표현식 형식은 다음과 같습니다:

함수 호출 표현식은 닫는 소괄호 바로 다음에 클로저 표현식의 형식으로 후행 클로저 (trailing closures) 를 포함할 수 있습니다. 이 후행 클로저는 마지막 괄호 인수 후에 추가된 함수의 인수로 이해됩니다. 첫번째 클로저 표현식은 라벨이 없습니다; 모든 추가 클로저 표현식은 인수 라벨이 앞에 옵니다. 아래 예제에서 후행 클로저 구문을 사용하거나 사용하지 않는 함수 호출의 동등한 버전을 보여줍니다:

// someFunction takes an integer and a closure as its arguments
someFunction(x: x, f: { $0 == 13 })
someFunction(x: x) { $0 == 13 }
// anotherFunction takes an integer and two closures as its arguments
anotherFunction(x: x, f: { $0 == 13 }, g: { print(99) })
anotherFunction(x: x) { $0 == 13 } g: { print(99) }

후행 클로저만 함수의 인수인 경우 소괄호를 생략할 수 있습니다.

// someMethod takes a closure as its only argument
myData.someMethod() { $0 == 13 }
myData.someMethod { $0 == 13 }

인수에 후행 클로저를 포함하려면 컴파일러는 다음과 같이 왼쪽에서 오른쪽으로 함수의 파라미터를 검사합니다:

후행 클로저

파라미터

동작

라벨

라벨

라벨이 동일하면 클로저는 파라미터와 매치됩니다; 그렇지 않으면 파라미터를 건너뜁니다.

라벨

라벨 없음

파라미터를 건너뜁니다.

라벨 없음

라벨 또는 라벨 없음

아래 정의된대로 파라미터가 구조적으로 함수 타입과 유사하면 클로저는 파라미터와 매치됩니다; 그렇지 않으면 파라미터를 건너뜁니다.

후행 클로저는 매치하는 파라미터에 대해 인수로 전달됩니다. 검색 프로세스 중에 건너뛴 파라미터에는 인수가 전달되지 않습니다—예를 들어 기본 파라미터를 사용할 수 있습니다. 일치하는 항목을 찾은 후에 다음 후행 클로저와 다음 파라미터 검색을 계속 합니다. 일치 프로세스가 끝나면 모든 후행 클로저는 매치되어야 합니다.

파라미터가 in-out 파라미터가 아니고 파라미터가 다음 중 하나인 경우 구조적 (structurally) 으로 함수 타입과 유사합니다 (resembles):

  • (Bool) -> Int 와 같이 타입이 함수 타입인 파라미터

  • @autoclosure () -> ((Bool) -> Int) 와 같이 래핑된 표현식의 타입이 함수 타입인 autoclosure 파라미터

  • ((Bool) -> Int)... 와 같이 배열 요소 타입이 함수 타입인 가변 파라미터

  • Optional<(Bool) -> Int> 와 같이 타입이 하나 이상의 옵셔널 레이어에 래핑된 파라미터

  • (Optional<(Bool) -> Int>)... 와 같이 타입이 이러한 허용된 타입을 결합하는 파라미터

후행 클로저는 타입이 함수 타입과 구조적으로 유사하지만 함수는 아닌 파리미터와 일치하면 클로저는 필요에 따라 래핑됩니다. 예를 들어 파라미터의 타입이 옵셔널 타입인 경우 클로저는 자동으로 Optional 로 래핑됩니다.

오른쪽에서 왼쪽으로 매칭을 수행하는 Swift 5.3 이전 버전에서 코드를 쉽게 마이그레이션 하기위해 컴파일러는 왼쪽에서 오른쪽과 오른쪽에서 왼쪽으로 모두 확인합니다. 검색 방향이 다른 결과를 가져오면 오래된 오른쪽에서 왼쪽 순서가 사용되고 컴파일러는 경고를 발생시킵니다. Swift 의 향후 버전은 항상 왼쪽에서 오른쪽 순서가 사용될 것입니다.

typealias Callback = (Int) -> Int
func someFunction(firstClosure: Callback? = nil,
secondClosure: Callback? = nil) {
let first = firstClosure?(10)
let second = secondClosure?(20)
print(first ?? "-", second ?? "-")
}
someFunction() // Prints "- -"
someFunction { return $0 + 100 } // Ambiguous
someFunction { return $0 } secondClosure: { return $0 } // Prints "10 20"

위의 예제에서 "Ambiguous" 로 표시된 함수 호출은 "- 120" 을 출력하고 Swift 5.3 에서 컴파일러는 경고가 발생합니다. Swift 햐우 버전은 "110 -" 이 출력될 것입니다.

클래스, 구조체, 또는 열거형 타입은 특수한 이름이 있는 메서드 (Methods with Special Names) 에서 설명한대로 여러 메서드 중 하나로 선언하여 함수 호출 구문에 대한 문법적 설탕 (syntactic sugar) 를 활성화 할 수 있습니다.

포인터 타입으로 암시적 변환 (Implicit Conversion to a Pointer Type)

함수 호출 표현식에서 인수와 파라미터가 다른 타입을 갖는 경우 컴파일러는 다음 목록의 암시적 변환 중 하나를 적용하여 해당 타입을 일치시키려고 합니다:

  • inout SomeTypeUnsafePointer<SomeType> 또는 UnsafeMutablePointer<SomeType> 이 될 수 있습니다.

  • inout Array<SomeType>UnsafePointer<SomeType> 또는 UnsafeMutablePointer<SomeType> 이 될 수 있습니다.

  • Array<SomeType>UnsafePointer<SomeType> 이 될 수 있습니다.

  • StringUnsafePointer<CChar> 가 될 수 있습니다.

다음 두가지 함수 호출은 동일합니다:

func unsafeFunction(pointer: UnsafePointer<Int>) {
// ...
}
var myNumber = 1234
unsafeFunction(pointer: &myNumber)
withUnsafePointer(to: myNumber) { unsafeFunction(pointer: $0) }

이러한 암시적 변환에 의해 생성된 포인터는 함수 호출 동안에만 유효합니다. 정의되지 않은 동작을 방지하려면 함수 호출이 끝난 후에 코드가 포인터를 유지되지 않도록 해야합니다.

NOTE 암시적으로 배열을 안전하지 않은 포인터 (unsafe pointer) 로 변환할 때 Swift 는 필요에 따라 배열을 변환하거나 복사하여 배열의 저장소가 연속되도록 합니다. 예를 들어 저장소에 대한 API 계약을 작성하지 않은 NSArray 하위클래스에서 Array 로 연결된 배열에 이 구문을 사용할 수 있습니다. 배열의 저장소가 이미 연속됨을 보장해야 하므로 암시적 변환은 이 작업을 수행할 필요가 없는 경우 Array 대신 ContiguousArray 를 사용하십시오.

withUnsafePointer(to:) 와 같이 명시적 함수 대신 & 사용하는 것은 특히 함수가 여러 포인터 인수를 가지고 있을 때 저수준 C 함수 (low-level C functions) 를 더 읽기 쉽게 호출할 수 있습니다. 그러나 다른 Swift 코드에서 함수를 호출할 때 안전하지 않은 API 를 명시적으로 사용하는 대신 & 을 사용하는 것은 피해야 합니다.

GRAMMAR OF A FUNCTION CALL EXPRESSION function-call-expression → postfix-expression function-call-argument-clause function-call-expression → postfix-expression function-call-argument-clause opt trailing-closures function-call-argument-clause → ( ) | ( function-call-argument-list ) function-call-argument-list → function-call-argument | function-call-argument , function-call-argument-list function-call-argument → expression | identifier : expression function-call-argument → operator | identifier : operator trailing-closures → closure-expression labeled-trailing-closures opt_{opt} labeled-trailing-closures → labeled-trailing-closure labeled-trailing-closures opt_{opt} labeled-trailing-closure → identifier : closure-expression

초기화 구문 표현식 (Initializer Expression)

초기화 구문 표현식 (initializer expression) 은 타입의 초기화 구문에 접근하는 것을 제공합니다. 형식은 다음과 같습니다:

타입의 새로운 인스턴스를 초기화하기 위해 함수 호출 표현식 내에 초기화 구문 표현식을 사용합니다. 상위클래스의 초기화 구문을 위임하기 위해 초기화 구문 표현식을 사용할 수도 있습니다.

class SomeSubClass: SomeSuperClass {
override init() {
// subclass initialization goes here
super.init()
}
}

함수와 같이 초기화 구문은 값으로 사용될 수 있습니다. 예를 들어:

// Type annotation is required because String has multiple initializers.
let initializer: (Int) -> String = String.init
let oneTwoThree = [1, 2, 3].map(initializer).reduce("", +)
print(oneTwoThree)
// Prints "123"

이름으로 타입을 지정하면 초기화 구문 표현식 사용없이 타입의 초기화 구문에 접근할 수 있습니다. 다른 모든 상황에서는 초기화 구문 표현식을 사용해야 합니다.

let s1 = SomeType.init(data: 3) // Valid
let s2 = SomeType(data: 1) // Also valid
let s3 = type(of: someValue).init(data: 7) // Valid
let s4 = type(of: someValue)(data: 5) // Error

GRAMMAR OF AN INITIALIZER EXPRESSION initializer-expression → postfix-expression . init initializer-expression → postfix-expression . init ( argument-names )

명시적 멤버 표현식 (Explicit Member Expression)

명시적 멤버 표현식 (explicit member expression) 은 명명된 타입, 튜플, 또는 모듈의 멤버에 접근을 허용합니다. 이것은 멤버의 아이템과 식별자 사이에 마침표 (.) 으로 구성됩니다.

명명된 타입의 멤버는 타입의 선언 또는 표현식의 부분으로 명명됩니다. 예를 들어:

class SomeClass {
var someProperty = 42
}
let c = SomeClass()
let y = c.someProperty // Member access

튜플의 멤버는 0을 시작으로 순서대로 정수를 사용하여 암시적으로 명명됩니다. 예를 들어:

var t = (10, 20, 30)
t.0 = t.1
// Now t is (20, 20, 30)

모듈의 멤버는 해당 모듈의 최상위 선언에 접근합니다.

dynamicMemberLookup 속성으로 선언된 타입은 속성 (Attributes) 에서 설명한대로 런타임 시 조회되는 멤버가 포함됩니다.

인수 이름만으로 이름이 다른 메서드 또는 초기화 구문을 구별하려면 인수 이름을 소괄호 안에 포함하고 각 인수 이름 뒤에 콜론 (:) 을 붙입니다. 인수에 이름이 없는 경우 언더바 (_) 를 작성합니다. 오버로드된 메서드를 구별하려면 타입 주석을 사용합니다. 예를 들어:

class SomeClass {
func someMethod(x: Int, y: Int) {}
func someMethod(x: Int, z: Int) {}
func overloadedMethod(x: Int, y: Int) {}
func overloadedMethod(x: Int, y: Bool) {}
}
let instance = SomeClass()
let a = instance.someMethod // Ambiguous
let b = instance.someMethod(x:y:) // Unambiguous
let d = instance.overloadedMethod // Ambiguous
let d = instance.overloadedMethod(x:y:) // Still ambiguous
let d: (Int, Bool) -> Void = instance.overloadedMethod(x:y:) // Unambiguous

줄 시작에 마침표가 나타나면 암시적 멤버 표현식이 아닌 명시적 멤버 표현식의 부분으로 이해됩니다. 예를 들어 다음 목록은 여러줄로 분할된 메서드 호출 체인을 보여줍니다:

let x = [10, 3, 20, 15, 4]
.sorted()
.filter { $0 > 5 }
.map { $0 * 100 }

GRAMMAR OF AN EXPLICIT MEMBER EXPRESSION explicit-member-expression → postfix-expression . decimal-digits explicit-member-expression → postfix-expression . identifier generic-argument-clause opt_{opt} explicit-member-expression → postfix-expression . identifier ( argument-names ) argument-names → argument-name argument-names opt_{opt} argument-name → identifier :

접미사 Self 표현식 (Postfix Self Expression)

접미사 self 표현식 (postfix self expression) 은 표현식 또는 타입의 이름 뒤에 .self 로 구성됩니다. 형식은 다음과 같습니다:

첫번째 형식은 표현식 (expression) 의 값으로 평가됩니다. 예를 들어 x.selfx 로 평가됩니다.

두번째 형식은 타입 (type) 의 값으로 평가됩니다. 값으로 타입을 접근하려면 이 형식을 사용합니다. 예를 들어 SomeClass.selfSomeClass 타입 자체로 평가되므로 타입 수준 인수 (type-level argument) 를 허용하는 함수나 메서드에 전달할 수 있습니다.

GRAMMAR OF A POSTFIX SELF EXPRESSION postfix-self-expression → postfix-expression . self

서브 스크립트 표현식 (Subscript Expression)

서브 스크립트 표현식 (subscript expression) 은 해당 서브 스크립트 선언의 getter 와 setter 를 사용하여 서브 스크립트에 접근을 제공합니다. 형식은 다음과 같습니다:

서브 스크립트 표현식의 값을 평가하기 위해 표현식 (expression) 의 타입에 대한 서브 스크립트 getter 는 서브 스크립트 파라미터로 인덱스 표현식 (index expressions) 을 전달하여 호출됩니다. 값을 설정하기 위해선 서브 스크립트 setter 는 동일한 방식으로 호출됩니다.

서브 스크립트 선언에 대한 자세한 내용은 프로토콜 서브 스크립트 선언 (Protocol Subscript Declaration) 을 참고 바랍니다.

GRAMMAR OF A SUBSCRIPT EXPRESSION subscript-expression → postfix-expression [ function-call-argument-list ]

강제-값 표현식 (Forced-Value Expression)

강제-값 표현식 (forced-value expression)nil 이 아니라고 확신하는 옵셔널 값을 언래핑 합니다. 형식은 다음과 같습니다:

표현식 (expression) 의 값이 nil 이 아니라면 옵셔널 값은 언래핑 되고 해당 옵셔널이 아닌 타입을 반환합니다. 그렇지 않으면 런타임 에러가 발생합니다.

강제-값 표현식의 언래핑된 값은 값 자체를 변경하거나 값의 멤버중 하나에 할당하여 수정할 수 있습니다. 예를 들어:

var x: Int? = 0
x! += 1
// x is now 1
var someDictionary = ["a": [1, 2, 3], "b": [10, 20]]
someDictionary["a"]![0] = 100
// someDictionary is now ["a": [100, 2, 3], "b": [10, 20]]

GRAMMAR OF A FORCED-VALUE EXPRESSION forced-value-expression → postfix-expression !

옵셔널-체이닝 표현식 (Optional-Chaining Expression)

옵셔널-체이닝 표현식 (optional-chaining expression) 은 접미사 표현식으로 옵셔널 값을 사용하기 위해 간단한 구문을 제공합니다. 형식은 다음과 같습니다:

접미사 ? 연산자는 표현식의 값 변경없이 표현식에서 옵셔널-체이닝 표현식을 만듭니다.

옵셔널-체이닝 표현식은 접미사 표현식 내에 나타나야 하고 접미사 표현식이 특별한 방법으로 평가되도록 합니다. 옵셔널-체이닝 표현식의 값이 nil 이면 접미사 표현식의 다른 모든 동작은 무시되고 전체 접미사 표현식은 nil 로 평가됩니다. 옵셔널-체이닝 표현식의 값이 nil 이 아니면 옵셔널-체이닝 표현식의 값은 언래핑되고 나머지 접미사 표현식에 평가하기 위해 사용됩니다. 두 경우 모두 접미사 표현식의 값은 여전히 옵셔널 타입입니다.

옵셔널-체이닝 표현식이 포함된 접미사 표현식이 다른 접미사 표현식 내에 중첩되었다면 가장 바깥쪽 표현식만 옵셔널 타입을 반환합니다. 아래의 예제에서 cnil 이 아닐 때 .performAction() 을 평가하기 위해 사용되는 .property 를 평가하는데 사용됩니다. 전체 표현식 c?.property.performAction() 은 옵셔널 타입의 값을 가집니다.

var c: SomeClass?
var result: Bool? = c?.property.performAction()

다음의 예제는 옵셔널 체이닝 사용없이 위의 예제의 동작을 보여줍니다.

var result: Bool?
if let unwrappedC = c {
result = unwrappedC.property.performAction()
}

옵셔널-체이닝 표현식의 언래핑된 값은 값 자체를 변경하거나 값의 멤버중 하나에 할당을 통해 변경될 수 있습니다. 옵셔널-체이닝 표현식의 값이 nil 이라면 할당 연산자의 오른편의 표현식은 평가되지 않습니다. 예를 들어:

func someFunctionWithSideEffects() -> Int {
return 42 // No actual side effects.
}
var someDictionary = ["a": [1, 2, 3], "b": [10, 20]]
someDictionary["not here"]?[0] = someFunctionWithSideEffects()
// someFunctionWithSideEffects isn't evaluated
// someDictionary is still ["a": [1, 2, 3], "b": [10, 20]]
someDictionary["a"]?[0] = someFunctionWithSideEffects()
// someFunctionWithSideEffects is evaluated and returns 42
// someDictionary is now ["a": [42, 2, 3], "b": [10, 20]]

GRAMMAR OF AN OPTIONAL-CHAINING EXPRESSION optional-chaining-expression → postfix-expression ?