关联类型

优质
小牛编辑
128浏览
2023-12-01

关联类型

  • 定义一个协议时, 有时在协议定义里声明一个或多个关联类型是很有用的. 关联类型给协议中用到的类型一个占位符名称. 直到采纳协议时, 才指定用于该关联类型的实际类型. 关联类型通过associatedtype关键字指定.

关联类型的应用

protocol Container {
    associatedtype ItemType
    mutating func append(_ item: ItemType)
    var count: Int { get }
    subscript(i: Int) -> ItemType { get }
}
  • 这个协议没有指定元素如何储存在容器中, 也没有指定允许存入容器的元素类型. 协议仅仅指定了想成为一个Container的类型, 必须提供的三种功能. 遵循该协议的类型可以提供其他功能, 只要满足这三个要求即可.

  • 任何遵循Container协议的类型必须能指定其存储值的类型. 尤其是它必须保证只有正确类型的元素才能添加到容器中, 而且该类型下标返回的元素类型必须是正确的.

  • 为了定义这些要求. Container协议需要一种在不知道容器具体类型的情况下, 引用该容器将存储的元素类型的方法. Container协议需要制定所有传给append(_:)方法的值必须和容器里元素的值类型一样的. 而且容器下标返回值也是和容器里元素的值类型相同.

个人理解: 感觉就是Swift在Protocol下定义泛型的一种语法标准, 如果按照struct的方式去定义protocol泛型, <T>这种写法会直接警报的

struct IntStack: Container {
    // original IntStack implementation
    var items = [Int]()
    mutating func push(_ item: Int) {
        items.append(item)
    }
    mutating func pop() -> Int {
        items.removeLast()
    }

    // conformance to the Container protocol
    typealias ItemType = Int
    mutating func append(_ item: Int) {
        self.push(item)
    }
    var count: Int {
        return items.count
    }
    subscript(i: Int) -> Int {
        return items[i]
    }
}

protocol Container {
    associatedtype ItemType
    mutating func append(_ item: ItemType)
    var count: Int { get }
    subscript(i: Int) -> ItemType { get }
}

泛型版本:

struct Stack<Element>: Container {
    // original IntStack implementation
    var items = [Element]()
    mutating func push(_ item: Element) {
        items.append(item)
    }
    mutating func pop() -> Element {
        items.removeLast()
    }

    // conformance to the Container protocol
    // Swift会自动推导出类型
    // typealias ItemType = Element 
    mutating func append(_ item: Element) {
        self.push(item)
    }
    var count: Int {
        return items.count
    }
    subscript(i: Int) -> Element {
        return items[i]
    }
}
protocol Container {
    associatedtype ItemType
    mutating func append(_ item: ItemType)
    var count: Int { get }
    subscript(i: Int) -> ItemType { get }
}

关联类型的约束

  • 你可以在协议里给关联类型添加约束来要求遵循的类型满足约束.
protocol Container {
    // 要求其元素遵循Equatable协议
    associatedtype ItemType: Equatable
    mutating func append(_ item: ItemType)
    var count: Int { get }
    subscript(i: Int) -> ItemType { get }
}
  • 协议也可以作为它自身的要求出现.
protocol SuffixableContainer {
    associatedtype SuffixableContainer: SuffixableContainer where Suffix.Item == Item
    func suffix(_ size: Int) -> Suffix
}