제네릭?
- 특정(Specific) 타입을 미리 지정해주는 것이 아닌 필요에 의해 지정할 수 있도록 하는 일반(Generic) 타입
- 타입에 유연한 대응, 재사용 쉬움, 중복 줄일 수 있음 → 깔끔하고 추상적인 표현 가능
타입 이름 <타입 매개변수>
타입 이름 <타입 매개변수> (함수의 매개변수)
제네릭 함수
- 플레이드 홀더 타입을 사용할 수 있음 (타입 매개변수), 함수에서 다음과 같이 사용 가능
- 여러개를 원한다면 <T, U, V>
- 되도록 의미있는 이름을 쓰자
제네릭 타입
- 사용자 정의 타입, 구조체, 열거형 클래스와 관련하여 어떤 타입과도 연관되어 동작할 수 있음.
- 한 타입을 지정해주면 그 타입으로 계속 동작, 처음 지정해주는 정도가 마음대로 가능한 것
제네릭 타입 확장
- 익스텐션을 통해 제네릭을 사용하는 타입에 기능을 추가할 때 익스텐션 정의에 <타입 매개변수> X
- 하지만 원래 제네릭 정의에 명시한 타입 매개변수를 익스텐션에서도 사용할 수 있음.
제네릭 타입 제약
- 종종 제약이 필요할 때가 있음
- 함수가 처리해야 할 기능이 특정 타입에 한정되어야만 처리할 수 있을 때
- 제네릭 타입을 특정 프로토콜을 따르는 타입만 사용할 수 있도록 제약을 둘 때
- 타입 제약 : 클래스 타입 또는 프로토콜로만 줄 수 있다.
- 제약 사항 지정 하면, 해당 클래스를 상속 받는 타입, 프로토콜을 준수하는 타입만 제네릭으로 들어올 수 있다.
- 타입 마다 제약을 다르게 사용할 수도 있다. 아래 Dictionary에서 Key, Value를 다르게 제약
public struct Dictionary<Key: Hashable, Value>: Collection, ... { }
- 제약을 추가하고 싶다면 where절을 사용해야 한다.
func swapValues<T: BinaryInteger>(_ a: inout T) where T: FloatingPoint { }
- 타입 제약에 자주 사용할 만한 프로토콜
- Hashable
- Equatable
- Comparable
- Indexable
- IteratorProtocol
- Error
- Collection
- CustomStringConvertible
프로토콜 연관 타입
- 연관타입(Associated Type)프로토콜에서 사용할 수 있는 플레이스 홀더 이름
protocol Container {
associatedtype ItemType
var count: Int { get }
mutating func append(_ item: ItemType)
subscript(i: Int) -> ItemType { get }
}
- 구현도 그냥 쓰면 되는데, 어떤 타입으로 사용할지 명확하게 해주고 싶다면 구현부에 타입 별칭 사용
typealias ItemType = Int
- 연관 타입을 실제 타입에 사용해도 되지만 제네릭 타입에 연관시키면 어떨까? 개꿀
struct Stack<Elemet>: Container {
var items = [Element]()
mutating func appent(_ item: Element) {
}
}