티스토리 뷰

programming/Swift

[Swift/iOS] 제네릭(2)

마들브라더 2022. 10. 21. 17:27

프로토콜의 연관 타입

  • 연관 타입은 프로토콜에서 사용할 수 있는 플레이스 홀더 이름
  • 연관 타입은 타입 매개변수의 그 역할을 프로토콜에서 수행할 수 있도록 만들어진 기능
  • 제네릭의 타입 매개변수와 유사하게 프로토콜 정의 내부에서 사용할 타입이 ‘그 어떤 것이어도 상관 없지만, 하나의 타입이다’라는 의미
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"]
댓글