0Pricing
Swift Academy · 课时

条件一致性

仅在满足约束时让泛型类型遵循协议。

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

什么是条件遵循

条件遵循让泛型类型仅在其类型参数满足特定约束时遵循某个协议。经典示例是:只有当 Array 的 Element 遵循 Equatable 时,Array 才遵循 Equatable。

extension Array where Element: Equatable {
    func allEqual(to x: Element) -> Bool {
        allSatisfy { $0 == x }
    }
}

内置示例

标准库已经使用了这一机制:[Int] 遵循 Equatable,因为 Int 遵循该协议。两个数组会逐个元素进行比较,以判断是否相等。

let a = [1, 2, 3]
let b = [1, 2, 3]
print(a == b)

声明条件遵循

请编写一个扩展,并通过 where 子句添加协议遵循。这里,只有当包装器的值类型也遵循 Equatable 时,包装器才遵循 Equatable。

struct Pair<T> {
    let first: T
    let second: T
}

extension Pair: Equatable where T: Equatable {
    static func == (l: Pair, r: Pair) -> Bool {
        l.first == r.first && l.second == r.second
    }
}

print(Pair(first: 1, second: 2) == Pair(first: 1, second: 2))

约束为何重要

如果没有该约束,编译器就无法合成 ==,因为比较包装的值要求该值本身可以进行比较。where 子句正好提供了这一保证。

struct Box<T> { let value: T }
extension Box: Equatable where T: Equatable {}

print(Box(value: "hi") == Box(value: "hi"))
print(Box(value: 5) == Box(value: 9))

条件可编码遵循

您也可以有条件地遵循 Codable。只有当容器的元素遵循 Codable 时,容器才可编码。

struct Wrapper<T> { let payload: T }
extension Wrapper: Codable where T: Codable {}

let w = Wrapper(payload: 42)
let data = try! JSONEncoder().encode(w)
print(String(data: data, encoding: .utf8)!)

多个约束

where 子句可以列出多个要求,并用逗号分隔。

struct Stack<T> { var items: [T] = [] }

extension Stack where T: Comparable {
    func maxItem() -> T? { items.max() }
}

var s = Stack<Int>()
s.items = [3, 9, 1]
print(s.maxItem()!)

条件 CustomStringConvertible 遵循

只有当一个类型的内容也支持打印时,才让该类型可打印,并根据各个元素组合出描述。

struct Labeled<T> { let label: String; let value: T }

extension Labeled: CustomStringConvertible where T: CustomStringConvertible {
    var description: String { label + ": " + value.description }
}

print(Labeled(label: "Age", value: 30))

嵌套的条件遵循

条件遵循可以组合:由 Int 组成的数组的数组遵循 Equatable,因为每一层都会传递这一约束。

let grid1 = [[1, 2], [3, 4]]
let grid2 = [[1, 2], [3, 4]]
print(grid1 == grid2)

约束为另一个协议

where 子句可以要求元素遵循您定义的协议,从而启用基于该协议的行为。

protocol Priced { var price: Double { get } }
struct Item: Priced { let price: Double }

extension Array where Element: Priced {
    var totalPrice: Double { reduce(0) { $0 + $1.price } }
}

print([Item(price: 1.5), Item(price: 2.5)].totalPrice)

同类型约束

您可以使用 == 将关联类型约束为特定类型。这里的方法仅适用于由 String 组成的数组。

extension Array where Element == String {
    func joinedUpper() -> String {
        map { $0.uppercased() }.joined(separator: "-")
    }
}

print(["a", "b", "c"].joinedUpper())

编译器如何使用它

条件遵循让编译器只在协议的功能确实有效时才提供这些功能,因此泛型代码既安全又具有最大的可复用性。

struct Optional2<T> { let value: T? }
extension Optional2: Equatable where T: Equatable {
    static func == (l: Optional2, r: Optional2) -> Bool { l.value == r.value }
}
print(Optional2(value: 1) == Optional2(value: 1))

快速检查

请检查您对条件遵循的理解。

回顾

条件遵循使用 extension Type: Protocol where ...,仅在类型参数满足约束时才授予协议遵循。您了解了它在 Equatable、Codable 和 CustomStringConvertible 中的应用,以及协议约束、同类型约束(==)和嵌套约束。它能让泛型类型既安全又可复用。

常见问题解答

「条件一致性」课时是免费的吗?

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

「条件一致性」这节课中我会学到什么?

仅在满足约束时让泛型类型遵循协议。 你通过在浏览器中直接运行的动手代码来练习 Swift Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Swift Academy 需要有经验吗?

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

「条件一致性」课时需要多长时间?

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

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

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

此课程中的所有课时

  1. 作为契约的协议
  2. 扩展中的默认实现
  3. 协议组合
  4. 条件一致性
← 返回 Swift Academy