반응형

[2019.03.11]

원문 : 애플 개발 문서 Swift 5.0 Language Reference - Types

타입(Types)

Swift에서는, 2 종류의 타입이 있습니다: 이름있는(named) 타입과 복합(compound) 타입. 이름있는 타입(named type)은 정의될때 특정 이름이 주어질수 있는 타입입니다. 이름있는(named) 타입은 클래스, 구조체, 열거형, 프로토콜을 포함합니다. 예를들어, MyClass라는 사용자가 정의한 클래스의 인스턴스는 MyClass 타입입니다. 사용자가 정의한 이름있는 타입외에도, Swift 표준 라이브러리는 일반적으로 많이 사용되는 이름있는 타입을 정의하며, 여기에는 배열, 딕셔너리, 옵셔널 값을 나타내는 것들을 포함합니다.

데이터 타입은 다른언어에서 일반적으로 기본(basic) 또는 원시적인(primitive)것으로 여겨지는 데이터 타입(숫자, 문자, 문자열을 표현하는 타입)은 실제로 이름있는 타입이며, Swift 표준라이브러리에서 구조체를 사용해서 정의되고 구현됩니다. 그것들은 이름있는 타입이기 때문에, 확장 선언을 사용해서, 프로그램의 요구에 맞게 행동을 확장할 수 있으며, Extensions와 Extension Declaration에서 논의됩니다.

복합 타입(compound type)은 이름이 없는 타입이며, Swift 언어에서 정의되어 있습니다. 이것들은 2개의 복합타입 입니다: 함수(function) 타입과 튜플(tuple) 타입. 복합 타입은 이름있는 타입과 다른 복합 타입을 포함할 수도 있습니다. 예를들어, 튜플 타입 (Int, (Int, Int))는 2개의 요소들을 포함합니다: 첫번째는 이름 있는 타입 Int, 두번재는 다른 복합 타입 (Int, Int)입니다.

이름있는 타입이나 복합 타입을 괄호로 묶을 수 있습니다. 하지만, 하나의 타입에 괄호를 추가해도 아무런 효과가 없습니다. 예를들어, (Int)는 Int와 같습니다.

이번 장(chapter)에서 Swift 언어 자체에 정의된 타입에 대해 논의(discusses)하고 Swift의 타입 추론 동작에 대해 설명합니다.

타입의 문법(grammar of a type)
type → array-type
type → dictionary-type
type → function-type
type → type-identifier
type → tuple-type
type → optional-type
type → implicity-unwrapped-optional-type
type → protocol-composition-type
type → metatype-type
type → Any
type → Self
type → { type }

타입 주석(Type Annotation)

타입 주석(type annotation)은 변수나 표현식의 타입을 명시적으로 지정합니다. 타입 주석은 다음에 오는 예제에서 보는것처럼, 콜론(:)으로 시작하고 타입으로 끝납니다.

let someTuple: (Double, Double) = (3.14159, 2.71828)
func someFunction(a: Int) { /* ... */ }

첫번째 예제에서는, 표현식 someTuple은 튜플 타입 (Double, Double)로 지정됩니다. 두번째 예제에서는, 함수 someFunction의 매개변수는 Int 타입으로 지정됩니다.

타입 주석은 타입 전에 옵셔널 타입 속성(attributes)의 목록을 포함할 수 있습니다.

타입 주석의 문법(grammar of a type annotation)
type-annotation → : attributesopt intoutopt type

타입 식별자(Type Identifier)

타입 식별자(type identifier)는 이름있는 타입이나 이름있는 타입 또는 복합 타입의 타입 별명(alias)중 하나를 참조합니다.

대부분의 경우에, 타입 식별자는 식별자로 이름있는 타입과 같은 이름을 참조합니다. 예를 들어, Int는 이름있는 타입 Int를 직접 참조하는 타입 식별자이고, 타입 식별자 Dictionary<String, Int>는 이름있는 타입 Dictionary<String, Int>를 직접 참조합니다.

타입 식별자가 동일한 이름으로 타입을 참조하지 않는 경우는 2가지가 있습니다. 첫번째의 경우는, 타입 식별자가 이름있거나 복합 타입의 타입 별명을 참조합니다. 예를들어, 아래 예제에서, 타입 주석에서 Point의 사용은 튜플 타입 (Int, Int)를 참조합니다.

typealias Point = (Int, Int)
let origin: Point = (0, 0)

두번째 경우에는, 타입 식별자가 다른 모듈의 이름있는 타입으로 선언되었거나 다른 타입에서 중첩된 참조하기 위해 점(.) 문법을 사용합니다. 예를들어, 다음에 오는 코드에서 타입 식별자는 ExampleModule 모듈에서 선언된 이름잇는 타입 MyType을 참조합니다.

var someValue: ExampleModule.MyType

타입 식별자의 문법(grammar of a type identifier)
type-identifier → type-name generic-argument-clauseopt | type-name generic-argument-clauseopt . type-identifier
type-identifier → identifier

튜플 타입(Tuple Type)

튜플 타입은 괄호로 안에, 콤마로 구분된 타입의 목록입니다.

함수가 여러 값을 포함하는 단일 튜플을 반환할수 있도록 함수의 반환타입으로 튜플 타입을 사용할 수 있습니다. 튜플 타입의 요소 이름을 지정하고 이러한 이름을 사용해서 개별 요소의 값을 참조할 수 있습니다. 요소 이름은 식별자가 바로 다음에 콜론(:)이 옵니다. 이러한 2가지 기능을 모두 보여주는 예제는, Functions with Multiple Return Values를 보세요.

튜플 타입의 요소가 이름을 가질때, 이름은 타입의 일부입니다.

var someTuple = (top: 10, bottom: 12)  // someTuple is of type (top: Int, bottom: Int)
someTuple = (top: 4, bottom: 42) // OK: names match
someTuple = (9, 99)              // OK: names are inferred
someTuple = (left: 5, right: 5)  // Error: names don't match

모든 튜플 타입은 2개 이상의 타입을 포함하며, 빈 튜플 타입 ()에 대한 타입 별명인 Void 는 예외입니다.

튜플 타입의 문법(grammar of a tuple type)
tuple-type → ( ) | ( tuple-type-elementtuple-type-element-list )
tuple-type-element-list → tuple-type-element | tuple-type-elementtuple-type-element-list
tuple-type-element → element-name type-annotation | type
element-name → identifier

함수 타입(Function Type)

함수 타입(function type)은 함수(function), 메소드(method) 또는 클로져(closure)와 매개변수로 구성되고 반환 타입이 화살표(->)로 구분된 타입을 표현합니다.

(parameter type) -> return type

매개변수 타입(parameter type)은 타입의 목록이 콤마(,)로 구분됩니다. 반환 타입(return type)은 튜플 타입이 될수 있기 때문에, 함수 타입은 함수와 메소드가 여러 값을 반환하는 것을 제공합니다.

() -> T(T는 타입) 함수 타입의 매개변수는 호출하는 곳에서 암묵적으로 클로져를 만들기 위해 autoclosure 속성을 적용할 수 있습니다. 함수를 호출할때 명시적인 클로져를 작성할 필요없이, 표현식의 평가를 미루기 위한 구문론적(syntactically)으로 편리한 방법을 제공합니다. autoclosure 함수 타입 매개변수의 예제는 Autoclosures를 보세요.

함수 타입은 매개변수 타입(parameter type)에 있는 가변(variadic) 변수를 가질 수 있습니다. 구문론적으로, 가변 매개변수는 Int...처럼, 기본 타입이름 바로 다음에 3개의 점(...)들로 구성됩니다. 가변 매개변수는 기본 타입 이름의 요소를 포함하는 배열로 처리됩니다. 예를들어, 가변 매개변수 Int...는 [Int]로 처리됩니다. 가변 매개변수를 사용하는 예제는, Variadic Parameters.

in-out 매개변수를 지정하기 위해, 매개변수 타입에 접두사로 inout 키워드를 붙입니다. inout 키워드로 가변 매개변수 또는 반환 타입을 표시할 수 없습니다. in-out 매개변수는 In-Out Parameters에서 논의됩니다.

함수 타입이 하나의 매개변수와 매개변수의 타입이 튜플타입인 경우에, 튜플 타입은 함수의 타입을 작성할때 괄호로 묶여있어야 합니다. 예를 들어, ((Int, Int)) -> Void는 (Int, Int) -> Void튜플 타입의 단일 매개변수를 가지고 아무런 값도 반환하지 않는 함수의 타입입니다. 이와는 대조적으로, 괄호가 없는 (Int, Int) -> Void는 2개의 Int 매개변수를 가지고 아무런 값도 반환하지 않는 함수의 타입입니다. 마찬가지로, Void는 ()에 대한 타입 별명이기 때문에, (Void) -> Void 함수 타입은 (()) -> ()와 같습니다 - 함수는 비어 있는 튜플인 단일 인자를 가집니다. 이 타입은 () -> ()과는 다릅니다 - 함수는 인자가 없습니다.

함수와 메소드에 있는 인자(argument) 이름은 해당 함수의 일부가 아닙니다. 예를 들어:

func someFunction(left: Int, right: Int) {}
func anotherFunction(left: Int, right: Int) {}
func functionWithDifferentLabels(top: Int, bottom: Int) {}

var f = someFunction // The type of f is (Int, Int) -> Void, not (left: Int, right: Int) -> Void.
f = anotherFunction              // OK
f = functionWithDifferentLabels  // OK

func functionWithDifferentArgumentTypes(left: Int, right: String) {}
f = functionWithDifferentArgumentTypes     // Error

func functionWithDifferentNumberOfArguments(left: Int, right: Int, top: Int) {}
f = functionWithDifferentNumberOfArguments // Error

인자 라벨은 함수의 타입의 일부가 아니기 때문에, 함수 타입을 작성할때 생략합니다.

var operation: (lhs: Int, rhs: Int) -> Int     // Error
var operation: (_ lhs: Int, _ rhs: Int) -> Int // OK
var operation: (Int, Int) -> Int               // OK

함수 타입이 하나 이상의 화살표(->)를 호함하는 경우, 그 함수 타입은 오른쪽에서 왼쪽으로 그룹화됩니다. 예를들어, (Int) -> (Int) -> Int함수 타입은 (Int) -> ((Int) -> Int)로 이해됩니다 - 즉, 함수는 하나의 Int를 가지고 Int를 가지고 반환하는 다른 함수를 반환합니다.

throws 키워드로 표시된 함수 타입은 오류를 던질수 있고, 함수 타입은 오류를 다시 던질 수(rethrow) 있는 경우에는 rethrows 키워드로 표시되어야만 합니다. throws 키워드는 함수의 타입의 일부이고, 오류를 던지는게 없는(nonthrowing) 함수는 오류를 던지는(throwing) 함수의 하위타입(subtype) 입니다. 결과적으로, 오류를 던지는(throwing) 것과 같은 곳에서 오류를 던지지는게 없는(nonthrowing) 함수를 사용할 수 있습니다. 오류를 던지고(throwing) 다시 던지는(rethrowing) 것은 Throwing Functions and Methods와 Rethrowing Functions and Methods에서 설명됩니다.

탈출하지 않는 클로져에 대한 제약사항(Restrictions for Nonescaping Closures)

탈출하지 않는(nonescaping) 함수인 매개변수는 값을 벗어날(escape) 수 있기 때문에, 어떤 타입의 프로퍼티, 변수, 상수로 저장될 수 없습니다.

탈출하지 않는(nonescaping) 함수인 매개변수는 다른 탈출하지 않는(nonescaping) 함수 매개변수에 인자로 전달할 수 없습니다. 이 제약사항은 Swift가 실시간 대신 컴파일시에 메모리에 충될되는 사용에 대해 더 많음 검사를 수행하는데 도움이 됩니다. 예를들어:

let external: (() -> Void) -> Void = { _ in () }
func takesTwoFunctions(first: (() -> Void) -> Void, second: (() -> Void) -> Void) {
    first { first {} }       // Error
    second { second {}  }    // Error

    first { second {} }      // Error
    second { first {} }      // Error

    first { external {} }    // OK
    external { first {} }    // OK
}

위 코드에서, takesTwoFunctions(first:second:)에 대한 매개변수 모두 함수입니다. 매개변수 모두 @escaping으로 표시되지 않았으므로, 결과적으로 둘다 탈출되지 않습니다(nonescaping).

위의 예제에서 Error이라고 표시된 3가지 함수는 컴파일 오류가 발생합니다. frist와 second 매개변수들이 탈출하지 않는(nonescaping) 함수이기 때문에, 다른 탈출하지 않는(nonescaping) 함수 매개변수로 인자로 전달될 수 없습니다. 이와는 대조적으로 OK라고 표시된 2가지 함수는 컴파일 오류가 발생하지 않습니다. 이 함수 호출은 external이 takesTwoFunctions(first:second:)의 매개변수중 하나가 아니기 때문에, 제약사항을 위반하지 않습니다.

이 제약사항을 피하려는 경우에, 매개변수 중 하나를 탈출(escaping)로 표시하거나 withoutActuallyEscaping(_:do) 함수를 사용해서 탈출하지 않는(nonescaping) 함수 매개변수 중 하나를 탈출 (escaping) 함수로 임시로 변환합니다. 메모리에 충돌을 피하는 것에 대한 정보는 Memory Safety를 보세요.

함수 타입의 문법(grammar of a function type)
function-type → attributesopt function-type-argument-clause throwsopt -> type
function-type → attributesopt function-type-argument-clause rethrows -> type

function-type-argument-clause → { }
function-type-argument-clause → { function-type-argument-list ...opt }

function-type-argument-list → function-type-argument | function-type-argument , function-type-argument-list
function-type-argument → attributesopt inoutopt type | argument-label type-annotation
function-type-argument-list → identifier

배열 타입(Array Type)

Swift 언어는 Swift 표준라이브러리 Array<Element> 타입에 대해 다음과 같은 문법을 제공합니다.

[type]

다시 말해서(In other words), 다음 2개의 선언은 동일합니다.

let someArray: Array<String> = ["Alex", "Brian", "Dave"]
let someArray: [String] = ["Alex", "Brian", "Dave"]

두 경우 모두, 상수 someArray는 문자열의 배열로 선언되어 있습니다. 배열의 요소는 대괄호([])안에 유효한 인덱스 값을 지정하는 서브스크립트로 사용될 수 있습니다: someArray[0]은 인덱스 0에 있는 "alex" 요소를 참조합니다.

대괄호 쌍을 중첩해서 다차원(multidimensional)의 배열을 만들 수 있으며, 요소들의 기본 타입의 이름은 대괄호 쌍의 가장 안쪽에 포함됩니다. 예를들어, 3개의 대괄호를 사용해서 정수형의 3차원 배열을 만들수 있습니다.

var array3D: [[[Int]]] = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]

다차원 배열에 있는 요소를 사용할때, 맨 왼쪽 서브스크립트 인덱스는 가장 바깥쪽 배열에 해당하는 인덱스의 요소를 참조합니다. 오른쪽에 있는 다음 서브스크립트는 한 단계 중첩된 배열에 해당하는 인덱스에 있는 요소를 참조합니다. 이는 위 예제에서, array3D[0]이 [[1, 2], [3, 4]]를 참조하며, array3D[0][1]은 [3, 4]를 참조하고, array3D[0][1][1]은 값 4를 참조합니다.

Swift 표준 라이브러리 Array 타입의 자세한 논의는 Arrays를 보세요.

배열 타입의 문법(grammar of an array type)
array-type → [ type ]

딕셔너리 타입(Dictionary Type)

Swift 언어는 Swift 표준 라이브러리 Dictionary<Key, Value> 타입에 대한 문법을 제공합니다.

[key type: value type]

다시 말해서(In other words), 다음에 오는 2개의 선언은 동일합니다.

let someDictionary: [String: Int] = ["Alex": 31, "Paul": 39]
let someDictionary: Dictionary<String, Int> = ["Alex": 31, "Paul": 39]

두 경우 모두, 상수 someDictionary는 문자열 키와 정수형 값으로 딕셔너리로 선언됩니다.

딕셔너리의 값은 대괄호 안에 해당하는 키(key)를 지정하는 서브스크립트를 통해서 사용될 수 있습니다: someDictionary["Alex"]는 "Alex"키와 연관된 값을 참조합니다. 서브스크립트는 딕셔너리의 값 타입의 옵셔널 값을 반환합니다. 딕셔너리에 지정된 키가 포함되지 않은 경우에, 서브스크립트는 nil을 반환합니다.

딕셔너리의 키(key) 타입은 Swift 표준 라이브러리 Hashable 프로토콜을 준수해야만 합니다.

Swift 표준 라이브러리 Dictionary 타입에 대한 자세한 논의는 Dictionaries를 보세요.

딕셔너리 타입의 문법(grammar of a dictionary type)
dictionary-type → [ type : type ]

옵셔널 타입(Optional Type)

Swift 언어는 이름있는 타입 Optional<Wrapped> 문법으로 접미사 ?를 정의하며, Swift 표준 라이브러리에서 정의됩니다. 다시 말해서(In other words), 다음 2개의 선언은 동일합니다.

var optionalInteger: Int?
var optionalInteger: Optional<Int>

두 경우 모두, optionalInteger 변수는 옵셔널 정수형의 타입으로 선언됩니다. 타입과 ? 사이에는 공백(whitespace)이 없어야 하는 것을 주의합니다.

Optional<Wrapped> 타입은 none와 some(Wrapped)로 된 2가지 케이스로 된 열거형이며, 현재 있거나 없을수도 있는 값을 표현하는데 사용됩니다. 모든 타입은 명시적으로 옵셔널 타입으로(또는 암시적으로 형변환) 선언될 수 있습니다. 옵셔널 변수나 프로퍼티를 선언할때 초기값을 제공하지 않으면, 그 값은 자동으로 기본값 nil입니다.

옵셔널 타입의 인스턴스에 값을 포함하는 경우, 아래에서 보는 것처럼, 접미사 연산자 !를 사용해서 값을 사용할 수 있습니다.

optionalInteger = 42
optionalInteger! // 42

! 연산자를 사용해서 nil인 옵셔널을 언래핑하면 런타입 오류가 발생합니다.

또한 옵셔널 표현식에서 조건부 실행을 수행하기 위해, 옵셔널 체이닝과 옵셔널 바인딩을 사용할 수 있습니다. 값이 nil인 경우, 아무런 연산도 수행되지 않고 따라서 런타임 오류도 발생하지 않습니다.

더 자세한 정보와 옵셔널을 사용하는 방법에 대한 예제를 보려면, Optionals을 보세요.

옵셔널 타입의 문법(grammar of an optional type)
optional-type → type ?

암시적으로 언래핑된 옵셔널 타입(Implicitly Unwrapped Optional Type)

Swift 언어는 이름있는 타입 Optional<Wrapped>에 대해 접미사 !를 정의하며, 이는 사용할때 자동으로 언래핑되도록 추가 동작하는, Swift 표준라이브러리에 정의되어 있습니다. nil 값을 가지고 있는데 암시적인 언래핑된 옵셔널을 사용하려는 경우, 런타임 오류가 발생할 것입니다. 암시적인 언래핑 동작을 제외하고 다음에 오는 2개의 선언은 동일합니다.

var implicitlyUnwrappedString: String!
var explicitlyUnwrappedString: Optional<String>

타입과 ! 사이에 공백(whitespace)가 보이지 않는 것을 주의합니다.

암시적인 언래핑은 해당 타입을 포함하는 선언의 의미를 변경하기 때문에, 튜플 타입이나 제네릭 타입(딕셔너리나 배열의 요소 처럼) 안에 중첩된 옵셔널 타입은 암시적으로 언래핑된 것으로 표시할 수 없습니다. 예를 들어:

let tupleOfImplicitlyUnwrappedElements: (Int!, Int!)  // Error
let implicitlyUnwrappedTuple: (Int, Int)!             // OK

let arrayOfImplicitlyUnwrappedElements: [Int!]        // Error
let implicitlyUnwrappedArray: [Int]!                  // OK

암시적으로 언래핑된 옵셔널은 옵셔널 값인 Optional<Wrapped> 타입을 가지기 때문에, 옵셔널을 사용할 수 있는 동일한 코드의 모든 곳에서 암시적으로 언래핑된 옵셔널을 사용할 수 있습니다. 예를들어, 암시적으로 언래핑된 옵셔널의 값을 변수, 상수, 옵셔널 프로퍼티에 할당할 수 있으며, 그 반대의 경우도 가능합니다.

옵셔널과 마찬가지로, 암시적으로 언래핑된 변수나 프로퍼티를 선언할때 초기 값을 제공하지 않는 경우에, 그 값은 자동적으로 기본값 nil입니다.

암시적으로 언래핑된 옵셔널 표현식에서 조건부 실행을 하기 위해 옵셔널 체이닝을 사용합니다. 값이 nil인 경우에, 아무런 작업도 수행되지 않고 따라서 런타임 오류가 발생하지 않습니다.

암시적으로 언래핑된 옵셔널 타입에 대한 자세한 정보는 Implicitly Unwrapped Optionals를 보세요.

암시적으로 언래핑된 옵셔널 타입의 문법
implicitly-unwrapped-optional-type → type !

프로토콜 합성 타입(Protocol Composition Type)

프로토콜 합성 타입은 지정된 프로토콜의 목록에서 각 프로토콜을 준수하는 타입으로 정의하거나 타입이 주어진 클래스의 하위클래스이고 지정된 프로토콜의 목록에서 각 프로토콜을 준수합니다. 프로토콜 합성 타입은 지정한 타입이 타입 주석, 일반 매개변수 클로져, 제네릭 where절 에서만 사용됩니다.

프로토콜 합성 타입은 다음과 같은 형식을 가집니다:

Protocol 1 & Protocol 2

프로토콜 합성 타입은 명시적으로 새로 정의하지 않고서, 여러개의 프로토콜의 요구사항을 준수하는 타입의 값을 지정할 수 있으며, 각 프로토콜에서 상속한 이름있는 프로토콜을 타입이 준수하길 원합니다. 예를 들어, ProtocolA & ProtocolB & ProtocolC인 프로토콜 합성 타입을 ProtocolA, ProtocolB, ProtocolC에서 상속받은 새로운 프로토콜 대신 사용할 수 있습니다. 비슷하게, SuperClass의 하위 클래스이고 ProtocolA를 준수하는 새로운 프로토콜을 선언하는 대신에 SuperClass & ProtocolA를 사용할 수 있습니다.

프로토콜 함성 목록에 있는 각 항목은 다음중 하나 입니다; 목록에는 최대 하나의 클래스를 포함할 수 있습니다.

  • 클래스의 이름
  • 프로토콜의 이름
  • 기본 타입이 프로토콜 합성 타입, 프로토콜 또는 클래스인 타입 별명(alias)

프로토콜 합성 타입이 타입 별명을 포함할때, 동일한 프로토콜이 정의에서 한번 이상 타나날 수 있습니다 - 중복은 무시됩니다. 예를들어, 아래 코드에 있는 PQR의 정의는 P & Q & R과 동일합니다.

typealias PQ = P & Q
typealias PQR = PQ & Q & R

프로토콜 합성 타입의 문법(grammar of a protocol composition type)
protocol-composition-type → type-identifier & protocol-composition-continuation
protocol-composition-continuation → type-identifier | protocol-composition-type

메타타입 타입(Metatype Type)

메타타입 타입은 모든 타입의 타입을 참조하며, 클래스 타입, 구조체 타입, 열거형 타입, 프로토콜 타입을 포함합니다.

클래스, 구조체, 열거형 타입의 메타타입은 다음에 오는 .Type으로 된 타입의 이름입니다. 프로토콜 타입의 메타타입(런타임에 프로토콜을 준수하는 구체적인 타입이 아닙니다)은 .Protocol으로된 프로토콜의 이름입니다. 예제에 대해서, SomeClass 클래스 타입의 메타타입은 SomeClass.Type이고 SomeProtocol 프로토콜의 메타타입은 SomeProtocol.Protocol 입니다.

타입을 값으로 사용하기 위해 접미사 self 표현식을 사용할 수 있습니다. 예를들어, SomeClass.self는 자체적으로 SomeClass를 반환하며, SomeClass의 인스턴스가 아닙니다. SomeProtocol.self는 SomeProtocol을 자체적으로 반환하며, 런타임에 SomeProtocol을 준수하는 타입의 인스턴스가 아닙니다. 다음 예제에서 보는 것 처럼, 인스턴스의 동적인 런타입 타입을 값 처럼 사용하기 위해 타입의 인스턴스가 있는 type(of:) 함수를 호출할 수 있습니다.

class SomeBaseClass {
    class func printClassName() {
        print("SomeBaseClass")
    }
}
class SomeSubClass: SomeBaseClass {
    override class func printClassName() {
        print("SomeSubClass")
    }
}
let someInstance: SomeBaseClass = SomeSubClass()
// The compile-time type of someInstance is SomeBaseClass,
// and the runtime type of someInstance is SomeSubClass
type(of: someInstance).printClassName()
// Prints "SomeSubClass"

더 자세한 정보는 Swift 표준 라이브러리에 있는 type(of:)를 보세요.

타입의 메타타입 값으로 타입의 인스턴스를 구성하기 위해 초기화 표현식을 사용합니다. 클래스 인스턴스에 대해서, 그 초기화는 required 키워드나 전체 클래스에서 final 키워드로 표시되서 호출됩니다.

class AnotherSubClass: SomeBaseClass {
    let string: String
    required init(string: String) {
        self.string = string
    }
    override class func printClassName() {
        print("AnotherSubClass")
    }
}
let metatype: AnotherSubClass.Type = AnotherSubClass.self
let anotherInstance = metatype.init(string: "some string")

메타타입 타입의 문법(grammar of a metatype type)
metatype-type → type . Type | type . Protocol

타입 상속 절(Type Inheritance Clause)

타입 상속 절은 이름있는 타입이 어떤 클래스에서 상속되고 어떤 프로토콜이 그 타입을 준수하는지, 상속클래스 지정하기 위해 사용됩니다. 타입 상속 절은 콜론(:)으로 시작하며, 바로 다음에 타입 식별자의 목록이 나옵니다.

클래스 타입은 하나의 상위클래스로 부터 상속할 수 있고 여러개의 프로토콜을 준수할 수 있습니다. 클래스를 정의할때 상위클래스의 이름은 타입의 식별자 목록에서 제일 먼저 나와야 하며, 다음에는 클래스가 반드시 준수해야만 하는 여러 프로토콜이 나옵니다. 클래스가 다른 클래스로부터 상속받지 않는 경우에, 목록은 프로토콜로 시작할 수 있습니다. 확장에 대한 토론과 클래스 상속의 여러 예제는, Inheritance를 보세요.

다른 이름있는 타입은 프로토콜의 목록에서만 상속되거나 준수할 수 있습니다. 프로토콜 타입은 다른 여러개의 프로토콜로부터 상속받을 수 있습니다. 다른 프로토콜로부터 프로토콜 타입을 상속받을때, 다른 프로토콜로 부터 요구사항을 설정은 함께 통합되고, 현재 프로토콜로부터 상속받는 모든 타입은 이러한 요구사항들을 모두 준수해야만 합니다.

열거형 정의에서의 타입 상속 절은 프로토콜의 목록이 될수 있거나, 원시 값을 할당하는 열거형의 경우에, 원시 값의 타입을 지정하는 하나의 이름있는 타입이 될 수 있습니다. 타입 상속 절을 사용해서 원시 값의 타입을 지정하는 열거형 정의에 대한 예제는 Raw Values를 보세요.

타입 상속 절의 문법(grammar of a type inheritance clause)
type-inheritance-clause → : type-inheritance-list
type-inheritance-list → type-identifier | type-identifier , type-inheritance-list

타입 추론(Type Inference)

Swift는 타입 추론을 광범위하게 사용하며, 많은 변수와 코드 표현식 타입 또는 타입의 일부를 생략할 수 있습니다. 예를들어, var x: Int = 0을 작성하는 대신에, var x = 0을 작성할 수 있으며, 타입을 완전히 생략합니다 - 컴파일러는 현재 x이름을 Int 타입의 값으로 추론합니다. 비슷하게, 모든 타입이 문맥상 추론될때, 타입의 일부를 생략할 수 있습니다. 예를들어, let dict: Dictionary = ["A": 1]을 작성하는 경우, 컴파일러는 dict가 Dictionary<String, Int> 타입을 가지는 것을 추론합니다.

위의 예제 모두, 타입 정보는 표현식 트리의 잎(leaves)에서 뿌리(root)까지 전달됩니다. var x: Int = 0에 있는 x의 타입은 0의 타입을 먼저 확인하기 위해 추론되고 타입 정보를 뿌리로 전달합니다.(변수 x)

Swift에서, 또한 타입 정보는 반대 방향으로도 진행될 수 있습니다- 뿌리에서 잎으로. 아래 예제에서, 인스턴스에 대해, eFloat 상수에서의 명시적인 타입 주석(: Float)은 숫자 리터럴 2.71828의 추론된 타입이 Double 대신에 Float가 됩니다.

let e = 2.71828 // The type of e is inferred to be Double.
let eFloat: Float = 2.71828 // The type of eFloat is Float.

Swift에서의 타입 추론은 단일 표현식이나 문장 수준에서 동작합니다. 이는 표현식에서 생략된 타입 또는 타입의 일부를 추론하는데 필요한 모든 정보는 표현식 또는 그 하위 표현식 중의 하나를 타입 검사를 통해서 사용할 수 있다는 것을 의미합니다.

반응형

'Swift > Language Reference' 카테고리의 다른 글

어휘 구조(Lexical Structure)  (0) 2019.03.08
언어 참조 정보(About the Language Reference)  (0) 2019.03.06
Posted by 까칠코더
,