타입파라미터

이전 포스팅에서 사용했던 swapTwoValues(::)를 보면

func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
    let temporaryA = a
    a = b
    b = temporaryA
}

placeholder 자료형 T가 바로 타입파라미터 입니다.

메서드 이름 바로 뒤에 명시해주며 <>안에 적어주면 됩니다.

타입파라미터를 지정해주면 우리는 메서드의 파라미티의 타입이나 반환값의 타입으로 사용할 수 있으며

혹은 메서드안에 주석으로 활용할 수도 있습니다.

메서드가 호출될때 타입파라미터의 실제 데이터타입을 명시해하여 타입을 구체화시킵니다.

또한 ,(쉼표)로 구분하여 타입파라미터를 여러개를 사용할 수 있습니다. 예를들면

struct Dictionary<Key, Value> where Key : Hashable

struct Array<Element> : _DestructorSafeContainer

스위프트의 컬렉션타입인 딕셔너리와 배열의 정의입니다. 딕셔너리에서는 Key와 Value라는 두개의 파라미터를

,(쉼표)를 사용해 구분하여 정의해주고 있습니다.



타입파라미터 네이밍

타입 파라미터의 이름은 Dictionary<Key, Value>에서 Key와 Value와 같이 각가가 타입 파라미터와

파라미터가 정의되어있는 타입이나 함수의 관계에서 역할로 이름을 짓습니다.

하지만 별다른 관계가 형성되지않을 경우에는 swapTwoValues(::)와 같이 T,U,V로 명시합니다.

타입파라미터를 명시할때는 타임파라미터가 값이 아니라 하나의 타입이므로 대문자로 Upper Camel Case로 표기해야합니다.



제네릭타입

제네릭을 활용하여 함수뿐만 아니라 타입또한 정의할 수 있습니다.

클래스, 구조체, 열거형에 적용할 수 있으며 배열과 딕셔너리같이 어떤 타입으로도 적용시킬 수 있습니다.

제네릭타입의 이해를 돕기위해 제네릭타입으로 정의한 Stack을 활용해보도록 하겠습니다.

Stack은 Array와 비슷하지만 조금 더 엄격한 규칙을 따르고 있습니다.

Array는 새로운 요소를 어느 위치에나 추가하고 삭제할 수 있는 반면에 Stack은 요소를 추가삭제할때 마지막 인덱스 값만을 수정합니다.(Last In First Out)

Stack에 새로운 요소를 추가하는것을 push 마지막 요소를 제거하는 것을 pop이라고 부릅니다.

  1. 현재 3개의 값이 스택안에 존재합니다.

  2. 4번째 값이 스택의 최상단에 push되었습니다.

  3. 스택에는 현재 4개의 값이 있고, 최상단에는 마지막에 push된 값이 있습니다.

  4. 최상단의 값이 pop되었습니다.

  5. pop된 후 스택에는 다시 세개의 값이 남아있습니다.


아래에 제네릭 타입이 아닌 Int형 스택 IntStack이 있습니다.

struct IntStack {
    var items = [Int]()
    mutating func push(_ item: Int) {
        items.append(item)
    }
    mutating func pop() -> Int {
        return items.removeLast()
    }
}

위의 구조체는 인스턴스 프로퍼티 items와 두개의 인스턴스 프로퍼티 push(_ item :)과 pop() -> Int로 구성되어 있습니다.

두 메서드는 items 프로퍼티에 변화를 주기때문에 mutating으로 명시되어있습니다.

IntStack은 Int타입으로써만 사용될 수 있지만 해당 타입을 제네릭타입으로 구현한다면 어떤 타입으로든 사용할 수 있습니다.


여기 제네릭으로 구현된 같은코드가 있습니다.

struct Stack<Element> {
    var items = [Element]()
    mutating func push(_ item: Element) {
        items.append(item)
    }
    mutating func pop() -> Element {
        return items.removeLast()
    }
}

제네릭타입은 제네릭메서드와 마찬가지로 타입의 이름 뒤에 타입파라미터를 <>를 통해 명시해줍니다.

Element는 추후에 사용될 타입의 placeholder자료형을 정의합니다. Element가 적용된 곳 어디든

타입내에서는 사용이 가능합니다.

제네릭타입으로 구현되었기에 Array와 Dictionary처럼 어떠한 타입으로든 사용될 수 있습니다.


아래와같이 <>안애 타입을 명시해줌으로써 제네릭타입 Stack의 인스턴스를 생성할 수 있습니다.

var stackOfStrings = Stack<String>()
stackOfStrings.push("uno")
stackOfStrings.push("dos")
stackOfStrings.push("tres")
stackOfStrings.push("cuatro")
// the stack now contains 4 strings



제네릭타입 extension

제네릭타입에 extension을 적용할때는 타입이름을 명시해주고 뒤에 placeholder자료형을 명시해줄 필요가 없습니다.

하지만 extension 구현을 할때 placeholder자료형인 Element를(위에서 예로들은 Stack의 경우) 바로 적용시킬 수 있습니다.

extension Stack {
    var topItem: Element? {
        return items.isEmpty ? nil : items[items.count - 1]
    }
}