타입에 의존하지 않는 범용 코드를 작성할 떄 사용한다.
⭐제네릭을 사용하면 중복을 피하고, 코드를 유연하게 작성할 수 있다.
두 Int 타입의 값을 변환하는 함수를 만든다면?
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let tempA = a
a = b
b = tempA
}
위의 함수는 Int 타입 말고, Double 이나 String 일 경우에는 사용할 수 없다.
이 때 사용하는 것이 바로 제네릭이다.
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
let tempA = a
a = b
b = tempA
}
"< >" 를 이용해서 안에 타입처럼 사용할 이름 (T)를 선언해주면
그 뒤로 해당 이름(T)를 타입처럼 사용할 수 있다.
여기서 T를 Type Parameter 라고 부른다.
이 때 T는 실제 함수가 호출될 때 해당 매개변수의 타입으로 대체되는 placeholder이다.
var someInt = 1
var aotherInt = 2
swapTwoValues(&someInt, &aotherInt) // 함수 호출 시 T는 Int 타입으로 결정됨
실제 함수를 호출할 때 Type Parameter인 T의 타입이 결정된다.
⭐이 때 someInt와 anotherInt는 같은 타입이기 때문에 에러가 없다.
⭐만약에 다르면? 에러난다.
제네릭 타입
제네릭을 이용한 함수를 "제네릭 함수" 라고 한다.
제네릭은 함수 뿐 아니라 구조체, 클래스, 열거형 타입에도 선언할 수 있다.
이를 "제네릭 타입" 이라고 한다.
struct Stack<T> {
let items: [T] = []
mutating func push(_ item: T) { ... }
mutating func pop() -> T { ... }
}
제네릭 타입의 인스턴스를 생성하려면?
선언과 마찬가지로 "< >"를 통해 어떤 타입으로 사용할 것인지를 명시해야 한다.
let stack1: Stack<Int> = .init()
let stack2 = Stack<Int>.init()