타입파라미터
이전 포스팅에서 사용했던 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이라고 부릅니다.
-
현재 3개의 값이 스택안에 존재합니다.
-
4번째 값이 스택의 최상단에 push되었습니다.
-
스택에는 현재 4개의 값이 있고, 최상단에는 마지막에 push된 값이 있습니다.
-
최상단의 값이 pop되었습니다.
-
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]
}
}