约束关联类型
在泛型上下文中限制关联类型。
约束关联类型 是 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 反馈 — 无需本地设置。