协议组合是 Swift 中的一个机制,允许创建一个需要同时遵循多个协议的类型。这是替代多重继承的一种方式,而在 Swift 中类是没有多重继承的。
问题背景
Objective-C 仅支持协议的多重继承,而不支持类的多重继承。Swift 继承了这个传统,更加重视协议及其组合来构建新的抽象。
问题
程序员通常面临的任务是创建一个类型,其行为由多个抽象定义。多重继承不可避免地导致层次冲突,而在 Swift 中通过协议和协议组合可以安全地解决这个问题。
解决方案
在 Swift 中,可以使用操作符 '&' 组合协议。这允许创建需要同时遵循多个协议的变量或函数参数。
代码示例:
protocol Drivable { func drive() } protocol Flyable { func fly() } struct FlyingCar: Drivable, Flyable { func drive() { print("驾驶中") } func fly() { print("飞行中") } } func testVehicle(_ vehicle: Drivable & Flyable) { vehicle.drive() vehicle.fly() } testVehicle(FlyingCar())
关键特点:
可以将仅实现其中一个协议的对象传递给协议组合的参数吗?
不可以,对象必须实现组合中参与的 所有 协议,否则编译器会报错。
代码示例:
// struct Car: Drivable {} — 不可以传递给 testVehicle,因为没有实现 fly()
协议组合是否仅适用于值而不适用于类型?
协议组合应用于值(变量、函数参数),但不用于定义对象类型(例如,不能声明新类型作为某种 "协议组合" — 只能是变量)。
代码示例:
var obj: SomeProtocol & AnotherProtocol // 合法 // typealias MyType = SomeClass & AnotherProtocol // 错误
可以通过 & 组合类和协议吗?
可以,但有一个限制:左侧只能有一个类类型(类或其子类),其余只能是协议,否则编译器会报错。
代码示例:
class A {} protocol B {} // func f(obj: A & B) {} // 合法 // func f(obj: A & AnotherClass & B) {} // 错误!只允许一个类类型
在一个项目中,虽然只需要一个协议,但却使用带有协议组合的对象进行层间数据传输:
func present(item: Displayable & Serializable) { ... }
优点:
仅在明确的情况下使用协议组合——例如,处理同时支持 Codable 和 Identifiable 以进行通用序列化的对象:
func save<T: Codable & Identifiable>(_ item: T) { ... }
优点: