제너릭 파라미터와 인수 (Generic Parameters and Arguments)

선언을 일반화하여 구체적인 타입을 추상화합니다.

이 챕터에서 제너릭 타입, 함수, 그리고 초기화 구문에 대한 파라미터와 인수를 설명합니다. 제너릭 타입, 함수, 서브 스크립트, 또는 초기화 구문을 선언할 때 제너릭 타입, 함수, 또는 초기화 구문이 동작할 수 있는 타입 파라미터를 지정합니다. 이러한 타입 파라미터는 제너릭 타입의 인스턴스가 생성되거나 제너릭 함수 또는 초기화 구문이 호출 될 때 실제 구체적인 타입 인수에 의해 대체되는 자리표시자 역할을 합니다.

Swift 의 제너릭에 대한 개요는 제너릭 (Generics) 을 참고 바랍니다.

제너릭 파라미터 절 (Generic Parameter Clause)

제너릭 파라미터 절 (generic parameter clause) 은 해당 파라미터의 관련된 모든 제약조건과 요구사항과 함께 제너릭 타입 또는 함수의 타입 파라미터를 지정합니다. 제너릭 파라미터 절은 꺾쇠 괄호 (<>) 로 둘러싸여 있고 다음의 형식을 가집니다:

<<#generic parameter list#>>

제너릭 파라미터 리스트 (generic parameter list) 는 콤마로 구분된 제너릭 파라미터의 리스트고 각각 다음의 형식을 가집니다:

<#type parameter#>: <#constraint#>

제너릭 파라미터는 타입 파라미터 (type parameter) 와 옵셔널 제약사항 (constraint) 으로 구성됩니다. 타입 파라미터 (type parameter) 는 자리표시자 타입의 간단한 이름입니다 (예를 들어 T, U, V, Key, Value, 등). 함수 또는 초기화 구문의 시그니처를 포함하는 나머지 타입, 함수, 또는 초기화 구문 선언에서 타입 파라미터와 모든 연관된 타입에 접근할 수 있습니다.

제약조건 (constraint) 은 타입 파라미터가 특정 클래스를 상속하거나 프로토콜 또는 프로토콜 구성을 준수하도록 지정합니다. 예를 들어 아래 제너릭 함수에서 제너릭 파라미터 T: Comparable 은 타입 파라미터 T 를 대신하는 모든 타입 인수는 Comparable 프로토콜을 준수해야 함을 나타냅니다.

func simpleMax<T: Comparable>(_ x: T, _ y: T) -> T {
    if x < y {
        return y
    }
    return x
}

예를 들어 IntDoubleComparable 프로토콜을 준수하므로 이 함수는 두 타입의 인수를 허용합니다. 제너릭 타입과 다르게 제너릭 함수 또는 초기화 구문을 사용할 때 제너릭 인수 절을 지정하지 않습니다. 대신에 타입 인수는 함수나 초기화 구문에 전달되는 인수의 타입으로 부터 추론됩니다.

simpleMax(17, 42) // T is inferred to be Int
simpleMax(3.14159, 2.71828) // T is inferred to be Double

제너릭 Where 절 (Generic Where Clauses)

타입이나 함수의 본문에 열린 괄호 직전에 제너릭 where 절을 포함하여 타입 파라미터와 연관된 타입의 요구사항을 추가로 지정할 수 있습니다. 제너릭 where 절은 where 키워드 다음에 콤마로 구분된 하나 이상의 요구사항 (requirements) 으로 구성됩니다.

where <#requirements#>

제너릭 where 절에서 요구사항 (requirements) 은 클래스를 상속하거나 프로토콜 또는 프로토콜 구성을 준수하는 타입 파라미터를 지정합니다. 제너릭 where 절은 예를 들어 <T: Comparable><T> where T: Comparable 과 동일하듯 타입 파라미터에 제약사항을 간단하게 표현하는 구문 설탕을 제공하지만 타입 파라미터와 연관된 타입에 더 복잡한 제약사항을 제공하기 위해 사용할 수 있습니다. 예를 들어 프로토콜을 준수하도록 타입 파라미터의 연관된 타입을 제한할 수 있습니다. 예를 들어 <S: Sequence> where S.Iterator.Element: EquatableSSequence 프로토콜을 준수하고 연관된 타입 S.Iterator.ElementEquatable 프로토콜을 준수하도록 지정합니다. 이 제약사항은 시퀀스의 각 요소는 동등함을 보장합니다.

== 연산자를 사용하여 두 타입이 동일해야 하는 요구사항을 지정할 수도 있습니다. 예를 들어 <S1: Sequence, S2: Sequence> where S1.Iterator.Element == S2.Iterator.ElementS1S2Sequence 프로토콜을 준수하고 두 시퀀스의 요소는 같은 타입이어야 한다는 제약사항이 있습니다.

타입 파라미터를 대체하는 모든 타입 인수는 타입 파라미터에 있는 모든 제약사항과 요구사항을 만족해야 합니다.

제너릭 where 절은 타입 파라미터를 포함하는 선언의 부분 또는 타입 파라미터를 포함하는 선언의 내부에 중첩된 선언의 부분으로 나타날 수 있습니다. 중첩된 선언에 대한 제너릭 where 절은 둘러싸는 선언의 타입 파라미터를 참조할 수 있습니다; 그러나 where 절의 요구사항은 작성된 선언에만 적용됩니다.

둘러싸는 선언도 where 절을 가지고 있으면 두 절의 요구사항은 결합됩니다. 아래 예제에서 startsWithZero()ElementSomeProtocolNumeric 모두 준수하는 경우에만 가능합니다.

extension Collection where Element: SomeProtocol {
    func startsWithZero() -> Bool where Element: Numeric {
        return first == .zero
    }
}

타입 파라미터에 다른 제약조건, 요구사항, 또는 둘 다 제공하여 제너릭 함수 또는 초기화 구문을 오버로드 할 수 있습니다. 오버로드 된 제너릭 함수 또는 초기화 구문을 호출할 때 컴파일러는 호출할 오버로드 된 함수 또는 초기화 구문을 확인하기 위해 이 제약조건을 사용합니다.

제너릭 where 절에 대한 자세한 정보와 제너릭 함수 선언의 예제를 보려면 제너릭 Where 절 (Generic Where Clauses) 을 참고 바랍니다.

Grammar of a generic parameter clause:

generic-parameter-clause< generic-parameter-list > generic-parameter-listgeneric-parameter | generic-parameter , generic-parameter-list generic-parametertype-name generic-parametertype-name : type-identifier generic-parametertype-name : protocol-composition-type

generic-where-clausewhere requirement-list requirement-listrequirement | requirement , requirement-list requirementconformance-requirement | same-type-requirement

conformance-requirementtype-identifier : type-identifier conformance-requirementtype-identifier : protocol-composition-type same-type-requirementtype-identifier == type

제너릭 인수 절 (Generic Argument Clause)

제너릭 인수 절 (generic argument clause) 은 제너릭 타입의 타입 인수를 지정합니다. 제너릭 인수 절은 꺾쇠 괄호 (<>) 로 둘러싸여져 있고 다음의 형식을 가집니다:

<<#generic argument list#>>

제너릭 인수 리스트 (generic argument list) 는 콤마로 구분된 타입 인수의 리스트입니다. 타입 인수 (type argument) 는 제너릭 타입의 제너릭 파라미터 절에서 해당 타입 파라미터를 대체하는 실제 구체적인 타입의 이름입니다. 결과는 해당 제너릭 타입의 특수 버전입니다. 아래 예제는 Swift 표준 라이브러리의 제너릭 딕셔너리 타입의 간단한 버전을 보여줍니다.

struct Dictionary<Key: Hashable, Value>: Collection, ExpressibleByDictionaryLiteral {
    /* ... */
}

제너릭 Dictionary 타입의 특수한 버전인 Dictionary<String, Int> 는 제너릭 파라미터 Key: HashableValue 를 구체적인 타입 인수 StringInt 로 대체하여 구성됩니다. 각 타입 인수는 제너릭 where 절에 지정된 추가 요구사항을 포함하여 대체하는 제너릭 파라미터의 모든 제약사항을 충족해야 합니다. 위의 예제에서 Key 타입 파라미터는 Hashable 프로토콜을 준수하도록 제한되므로 StringHashable 프로토콜을 준수해야 합니다.

타입 파라미터를 적절한 제약사항과 요구사항을 충족하는 경우 그 자체가 제너릭 타입의 특별한 버전인 타입 인수로 대체할 수 있습니다. 예를 들어 요소 자체가 정수의 배열인 Array<Int>Array<Element> 배열의 특별한 버전으로 타입 파라미터 Element 를 대체할 수 있습니다.

let arrayOfArrays: Array<Array<Int>> = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

제너릭 파라미터 절 (Generic Parameter Clause) 에서 언급했듯이 제너릭 함수 또는 초기화 구문의 타입 인수로 지정하기 위해 제너릭 인수 절을 사용하지 않습니다.

Grammar of a generic argument clause:

generic-argument-clause< generic-argument-list > generic-argument-listgeneric-argument | generic-argument , generic-argument-list generic-argumenttype

Last updated