프로토콜의 연관 타입
- 연관 타입은 프로토콜에서 사용할 수 있는 플레이스 홀더 이름
- 연관 타입은 타입 매개변수의 그 역할을 프로토콜에서 수행할 수 있도록 만들어진 기능
- 제네릭의 타입 매개변수와 유사하게 프로토콜 정의 내부에서 사용할 타입이 ‘그 어떤 것이어도 상관 없지만, 하나의 타입이다’라는 의미
protocol Container {
associatedtype ItemType // 연관 타입 정의
var count: Int { get } // 아이템 개수 확인
mutating func append(_ item: ItemType) // 아이템 추가
subscript(i: Int) -> ItemType { get } // 인덱스 값으로 아이템을 가져오기
}
class MyContainer: Container {
var items = Array<Int>()
var count: Int {
return items.count
}
func append(_ item: Int) {
items.append(item)
}
subscript(i: Int) -> Int {
return items[i]
}
}
- 위 코드는 연관타입 ItemType을 정의하고, 클래스 구현할 때는 Int로 구현
// StringStack 구조체의 Container 프로토콜 준수, 프로토콜에서는 Int -> String으로 수정
struct StringStack: Container {
var items = [String]()
mutating func push(_ item: String) {
items.append(item)
}
mutating func pop() -> String {
return items.removeLast()
}
var count: Int {
get {
return items.count
}
}
mutating func append(_ item: String) {
items.append(item)
}
subscript(i: Int) -> String {
return items[i]
}
}
- ItemType 대신 String을 사용해서 구현
- 어떤 타입으로 명시하고 싶으면 구조체 구현부에 typealias ItemType = String 이라고 지정 가능
// typealias 사용한 StringStack
struct StringStack: Container {
typealias ItemType = String
var items = [ItemType]()
mutating func push(_ item: ItemType) {
items.append(item)
}
mutating func pop() -> ItemType {
return items.removeLast()
}
var count: Int {
get {
return items.count
}
}
mutating func append(_ item: ItemType) {
items.append(item)
}
subscript(i: Int) -> ItemType {
return items[i]
}
}
- 연관타입에 대응해서 실제 타입을 사용할 수도 있지만, 제네릭 타입도 사용 가능
struct StringStack<T>: Container {
var items = [T]()
mutating func push(_ item: T) {
items.append(item)
}
mutating func pop() -> T {
return items.removeLast()
}
var count: Int {
get {
return items.count
}
}
mutating func append(_ item: T) {
items.append(item)
}
subscript(i: Int) -> T {
return items[i]
}
}
제네릭 서브스크립트
- 서브스크립트도 제네릭을 활용하여 구현 가능
- 타입 제약을 사용하여 제약을 줄 수 있음
extension StringStack {
subscript<Indices: Sequence>(indices: Indices) -> [T] where Indices.Iterator.Element == Int {
var result = [T]()
for index in indices {
result.append(self[index])
}
return result
}
}
var strings = StringStack<String>()
for number in 0...5 {
strings.append(String(number))
}
print(strings[0...5]) // ["0", "1", "2", "3", "4", "5"]