685  字
  3  分钟 
  Swift 不透明类型与装箱协议类型 
 **不透明类型(Opaque Types)和装箱协议类型(Boxed Protocol Types)**是两种重要的类型抽象工具,允许开发者隐藏类型细节,提升代码的灵活性和模块化程度。
不透明类型(some)
1. 定义与特性
不透明类型通过 some 关键字声明,对外隐藏具体类型,但编译器在编译期知晓实际类型。例如:
func makeTrapezoid() -> some Shape {    let top = Triangle(size: 2)    let bottom = FlippedShape(shape: top)    return JoinedShape(top: top, bottom: bottom)}- 类型隐藏:调用者仅知返回值遵循 Shape协议,不感知内部的JoinedShape类型。
- 编译期优化:编译器静态确定类型,避免运行时开销。
- 反向泛型:与泛型由调用者决定类型不同,不透明类型由函数实现决定类型。
2. 使用场景
- 模块接口设计:保护内部类型细节,如图形变换操作返回 some Shape。
- 关联类型协议:解决带关联类型的协议无法直接作为返回类型的问题(如 some Container)。
装箱协议类型(any)
1. 定义与特性
装箱协议类型(存在类型)通过 any 关键字声明,允许存储任意遵循协议的具体类型:
struct VerticalShapes: Shape {    var shapes: [any Shape] // 可存储不同具体类型    func draw() -> String { /* 绘制所有形状 */ }}- 动态类型:具体类型在运行时确定,支持存储异构集合(如同时存放 Triangle和Square)。
- 性能开销:需要运行时类型检查和内存装箱操作。
2. 局限性
- 类型信息丢失:无法直接访问具体类型的特有属性和方法,需通过 as?向下转型。
- 操作限制:依赖具体类型的操作(如 ==比较)可能不可用。
对比
| 特性 | 不透明类型 ( some) | 装箱协议类型 ( any) | 
|---|---|---|
| 类型确定性 | 编译期确定单一类型 | 运行时动态支持多类型 | 
| 性能 | 无运行时开销 | 有装箱和类型检查开销 | 
| 使用场景 | 模块接口隐藏实现细节 | 异构集合存储 | 
| 类型标识保留 | ✅ | ❌ | 
| 泛型嵌套支持 | ✅(如 flip(flip(shape))) | ❌(多次变换后类型不兼容) | 
实践
- 
优先使用不透明类型 
 当需要隐藏类型且编译期可确定时(如模块返回值),选择some以提升性能和安全性。
- 
谨慎使用装箱类型 
 仅在需要动态类型(如混合存储不同类型)时使用any,并注意其性能影响。
- 
结合泛型增强灵活性 
 不透明类型可与泛型结合,例如:func flip<T: Shape>(_ shape: T) -> some Shape {FlippedShape(shape: shape)}这种方式既隐藏类型,又支持泛型参数传递。 
 Swift 不透明类型与装箱协议类型 
  https://blog.lpkt.cn/posts/swift-opaque-box-types/     
  