0Pricing
Swift Academy · 课时

协议组合

使用 & 组合多个协议要求。

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

组合协议

有时一个值必须同时满足多个协议。Swift 允许您使用 & 运算符组合协议:SomeProtocol & AnotherProtocol。

protocol Named { var name: String { get } }
protocol Aged { var age: Int { get } }

组合类型参数

类型为 Named & Aged 的参数可以接受同时遵循这两个协议的任意值。

protocol Named { var name: String { get } }
protocol Aged { var age: Int { get } }

struct Person: Named, Aged {
    let name: String
    let age: Int
}

func intro(_ x: Named & Aged) {
    print(x.name + " is " + String(x.age))
}
intro(Person(name: "Sam", age: 28))

为什么不使用继承

组合可以让您在调用处要求同时遵循两个协议,而不必创建新的组合协议。这样可以使协议保持小巧并且易于复用。

protocol Drawable { func draw() -> String }
protocol Resizable { func resize(_ f: Double) -> String }

struct Icon: Drawable, Resizable {
    func draw() -> String { "drawing" }
    func resize(_ f: Double) -> String { "x" + String(f) }
}

func render(_ v: Drawable & Resizable) {
    print(v.draw(), v.resize(2))
}
render(Icon())

三个或更多协议

您可以使用额外的 & 运算符链接任意数量的协议。

protocol A { func a() -> String }
protocol B { func b() -> String }
protocol C { func c() -> String }

struct X: A, B, C {
    func a() -> String { "a" }
    func b() -> String { "b" }
    func c() -> String { "c" }
}

func use(_ v: A & B & C) { print(v.a(), v.b(), v.c()) }
use(X())

将类与协议组合

您可以将类类型与协议组合:SomeClass & SomeProtocol 要求该值属于该类(或其子类)AND 遵循该协议。

class Vehicle { var speed = 0 }
protocol Electric { var battery: Int { get } }

class Tesla: Vehicle, Electric { var battery = 100 }

func check(_ v: Vehicle & Electric) {
    print(v.speed, v.battery)
}
check(Tesla())

返回组合类型

函数可以返回组合类型,向调用者保证结果遵循列出的所有协议。

protocol Named { var name: String { get } }
protocol Aged { var age: Int { get } }
struct Person: Named, Aged { let name: String; let age: Int }

func makePerson() -> Named & Aged {
    Person(name: "Eve", age: 22)
}
let p = makePerson()
print(p.name, p.age)

组合的类型别名

使用 typealias 为组合类型指定一个易读的名称,这样就可以复用它,而不必重复 & 链。

protocol Codable2 { func encode() -> String }
protocol Loggable { func log() -> String }

typealias Persistable = Codable2 & Loggable

struct Record: Persistable {
    func encode() -> String { "data" }
    func log() -> String { "logged" }
}
func save(_ r: Persistable) { print(r.encode(), r.log()) }
save(Record())

集合中的组合类型

您可以将组合类型的值存储在数组中,并访问每个元素所遵循的所有协议成员。

protocol Named { var name: String { get } }
protocol Aged { var age: Int { get } }
struct P: Named, Aged { let name: String; let age: Int }

let group: [Named & Aged] = [P(name: "A", age: 1), P(name: "B", age: 2)]
for g in group { print(g.name, g.age) }

与标准协议组合

组合与库中的协议结合使用时尤其有用。例如,可以同时要求遵循 CustomStringConvertible 和 Equatable。

func report<T>(_ items: [T]) where T: CustomStringConvertible & Equatable {
    for i in items { print(i.description) }
}
report([1, 2, 3])

作为标记的空协议

组合可以将标记协议(没有要求)与功能型协议结合起来,从而在类型系统中表达意图。

protocol Secure {}
protocol Sendable2 { func send() -> String }

struct Packet: Secure, Sendable2 {
    func send() -> String { "sent securely" }
}
func transmit(_ p: Secure & Sendable2) { print(p.send()) }
transmit(Packet())

组合与泛型的比较

组合(A & B)会擦除具体类型;泛型(<T: A & B>)则会保留它。当您需要关联参数类型和返回类型时,请使用泛型。

protocol A { func a() -> String }
protocol B { func b() -> String }
struct S: A, B { func a() -> String { "a" }; func b() -> String { "b" } }

func generic<T: A & B>(_ x: T) -> T { print(x.a(), x.b()); return x }
_ = generic(S())

快速检查

请检查您对协议组合的理解。

回顾

使用 & 进行协议组合,可以同时要求遵循多个协议(以及可选的一个类),而无需定义新的组合协议。您可以使用 typealias 为组合命名,将其用于参数、返回值和集合中;同时还了解了组合与泛型在保留具体类型方面的区别。

常见问题解答

「协议组合」课时是免费的吗?

是的 — 「协议组合」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 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. 扩展中的默认实现
  3. 协议组合
  4. 条件一致性
← 返回 Swift Academy