5月27日 11:27

Swift 协议是什么?协议扩展和面向协议编程怎么理解?

协议定义了一组属性和方法的蓝图,任何类型都可以遵循协议来实现这些要求。Swift 的协议比 Java 的接口更强——它支持默认实现(通过协议扩展)、协议组合、关联类型,是面向协议编程(POP)的核心。

协议本身不实现功能,只定义"需要什么"。遵循协议的类型必须提供具体实现。协议可以作为类型使用——函数参数、变量、集合元素都可以是协议类型,实现多态。

追问

协议扩展的默认实现有什么用?

协议扩展可以为协议方法提供默认实现,遵循协议的类型如果不自己实现,就自动用默认的。这解决了两个问题:一是不需要每个遵循类型都写一遍相同逻辑;二是可以给协议添加新方法而不破坏已有的遵循类型。标准库里大量用了这个特性——Collection 协议的 map、filter 都是协议扩展提供的默认实现。

协议组合是什么?和继承有什么区别?

ProtocolA & ProtocolB 把多个协议组合成一个临时类型,不需要定义新的协议。和继承的区别:组合是"有这些能力",继承是"是一种"。一个类型可以同时遵循任意多个协议(组合),但只能继承一个父类(单继承)。实际开发中,优先用协议组合代替继承——更灵活,耦合更低。

关联类型是什么?什么时候用?

协议里用 associatedtype 声明一个占位类型,由遵循协议的具体类型来确定。比如 Collection 协议的 Element 就是关联类型——Array 的 Element 是具体类型,Dictionary 的 Element 是键值对。有关联类型的协议不能直接当类型用(不能用 let x: SomeProtocol),需要用泛型约束 some SomeProtocolany SomeProtocol

any 和 some 关键字有什么区别?

any Protocol 是存在类型(existential),运行时可以是任何遵循协议的类型,有动态派发开销。some Protocol 是不透明类型,编译期确定具体类型,性能更好。Swift 5.7 开始,协议类型的变量必须显式写 any,否则编译器警告。函数返回值用 some 可以隐藏具体类型同时保证性能。

面向协议编程(POP)比 OOP 好在哪?

POP 用协议+扩展代替继承,解决了 OOP 的几个痛点:单继承限制(协议可以组合多个)、脆弱基类问题(协议扩展不依赖继承链)、强耦合(协议只定义接口,不绑定实现)。Swift 标准库本身就是面向协议设计的——Array 遵循 Collection 协议获得几十个方法,而不是继承自某个基类。

写段代码

swift
protocol Drawable { func draw() } // 协议扩展提供默认实现 extension Drawable { func draw() { print("默认绘制") } } protocol Scalable { var scale: CGFloat { get set } mutating func resize(to scale: CGFloat) } // 协议组合 func render(_ item: some Drawable & Scalable) { item.draw() } // 关联类型 protocol Container { associatedtype Item var count: Int { get } mutating func append(_ item: Item) subscript(i: Int) -> Item { get } } struct Stack<Element>: Container { private var items: [Element] = [] var count: Int { items.count } mutating func append(_ item: Element) { items.append(item) } subscript(i: Int) -> Element { items[i] } }
标签:Swift