0Pricing
Swift Academy · 课时

约束关联类型

在泛型上下文中限制关联类型。

约束关联类型 是 CoddyKit 上的免费 Swift Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Swift Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Swift Academy 课程共包含 4 节课。

关联类型回顾

协议可以使用 associatedtype 声明关联类型,这是一个由遵循该协议的类型填充的占位符。容器协议中的 Element 就是经典示例。

protocol Container {
    associatedtype Item
    var count: Int { get }
    func item(at i: Int) -> Item
}

使用具体类型遵循协议

遵循协议的类型会确定关联类型;该类型通常可以根据其使用方式推断出来。

protocol Container {
    associatedtype Item
    func item(at i: Int) -> Item
}
struct IntBox: Container {
    let values: [Int]
    func item(at i: Int) -> Int { values[i] }
}
print(IntBox(values: [10, 20]).item(at: 1))

约束关联类型

请直接在声明中添加约束:associatedtype Item: Comparable 会强制每个遵循者的项目类型都支持比较。

protocol Sorted {
    associatedtype Item: Comparable
    var items: [Item] { get }
}
struct Nums: Sorted { let items: [Int] }
print(Nums(items: [3, 1, 2]).items.sorted())

使用约束

由于关联类型受到约束,协议扩展可以依赖该能力。

protocol Sorted {
    associatedtype Item: Comparable
    var items: [Item] { get }
}
extension Sorted {
    var smallest: Item? { items.min() }
}
struct Nums: Sorted { let items: [Int] }
print(Nums(items: [5, 2, 8]).smallest!)

关联类型上的 where

Swift 还允许在关联类型上使用 where 子句,将它与另一个关联类型或嵌套类型关联起来。

protocol Sequence2 {
    associatedtype Element
    associatedtype Iterator: IteratorProtocol where Iterator.Element == Element
}

约束为另一个协议

可以要求关联类型遵循您定义的协议,从而分层组合行为。

protocol HasName { var name: String { get } }
protocol Registry {
    associatedtype Entry: HasName
    var entries: [Entry] { get }
}
struct User: HasName { let name: String }
struct Users: Registry { let entries: [User] }
print(Users(entries: [User(name: "Ada")]).entries[0].name)

多个关联类型

一个协议可以声明多个关联类型,并分别对它们进行约束。

protocol Mapping {
    associatedtype Key: Hashable
    associatedtype Value
    func value(for k: Key) -> Value?
}
struct Phonebook: Mapping {
    let data: [String: Int]
    func value(for k: String) -> Int? { data[k] }
}
print(Phonebook(data: ["x": 1]).value(for: "x")!)

默认关联类型

您可以使用 = 为关联类型提供默认类型;当遵循者没有另外指定时,就会使用该类型。

protocol Producer {
    associatedtype Output = String
    func make() -> Output
}
struct Hello: Producer {
    func make() -> String { "hi" }
}
print(Hello().make())

约束支持泛型算法

有了受约束的关联类型,协议扩展就可以实现供所有遵循者共享的实际算法。

protocol Scored {
    associatedtype Score: Comparable
    var scores: [Score] { get }
}
extension Scored {
    var best: Score? { scores.max() }
}
struct Game: Scored { let scores: [Int] }
print(Game(scores: [10, 40, 25]).best!)

扩展中的同类型约束

在协议之外扩展协议时,您可以进一步约束关联类型。

protocol Box2 {
    associatedtype Content
    var content: Content { get }
}
extension Box2 where Content == Int {
    var doubled: Int { content * 2 }
}
struct IB: Box2 { let content: Int }
print(IB(content: 7).doubled)

为什么要添加约束

约束关联类型可以让协议既保持泛型特性又具备强大能力:该约束是扩展和调用方都可以依赖的承诺。

protocol Listy {
    associatedtype E: Equatable
    var elements: [E] { get }
}
extension Listy {
    func has(_ x: E) -> Bool { elements.contains(x) }
}
struct L: Listy { let elements: [String] }
print(L(elements: ["a", "b"]).has("b"))

快速检查

请检查您对关联类型约束的理解。

回顾

您可以直接约束关联类型(associatedtype Item: Comparable),使用 where 子句关联它们,要求它们遵循协议,使用 = 提供默认类型,声明多个关联类型,并在扩展中进一步细化它们。约束让协议扩展可以实现共享且类型安全的算法。

常见问题解答

「约束关联类型」课时是免费的吗?

是的 — 「约束关联类型」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Swift Academy 课程的其余内容,请升级到 CoddyKit PRO。 Swift Academy 课程共包含 4 节课。

「约束关联类型」这节课中我会学到什么?

在泛型上下文中限制关联类型。 你通过在浏览器中直接运行的动手代码来练习 Swift Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Swift Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Swift Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「约束关联类型」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Swift Academy 课中编写并运行代码吗?

能。每节 Swift Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 类型参数约束
  2. 函数上的 where 子句
  3. 约束关联类型
  4. 泛型下标与扩展
← 返回 Swift Academy