问题背景:
Opaque types (some) 于Swift 5.1推出,开启了一种新的方式来抽象函数或属性的返回值,当类型对编译器已知但对用户隐藏时。这是protocol existentials (any Protocol) 的替代方案,但严格绑定于函数内部的特定类型。
问题: 当一个函数返回一个带有associatedtype的协议(例如,Sequence)时,无法直接编写:
func makeNumberSequence() -> Sequence { ... } // 错误
Protocol existentials允许返回任何实现,但不会保证每次调用时返回相同的类型:
func foo() -> any View { ... }
这导致不可预测性和弱类型安全。
解决方案: 使用opaque result type:
func makeNumbers() -> some Sequence { [1, 2, 3] }
现在编译器确切知道实际返回的类型,但它在外部是隐藏的。这提供了性能优化、安全性,允许使用SwiftUI DSL,简化模块间的类型交换。
关键特性:
opaque types可以用于存储值(作为类的属性)吗?
不可以。Opaque types仅用于函数的返回值或计算属性。存储值或值数组时使用existentials (any Protocol)。
同一个函数的不同分支可以返回不同类型的some吗?
不可以。编译器要求所有分支返回相同的具体类型,否则会报错:
func foo(flag: Bool) -> some Sequence { if flag { return [1, 2, 3] } else { return ["a", "b", "c"] // 错误 } }
可以使用some来识别多个函数之间的返回类型吗?
不可以。每个带有some的函数返回其唯一的隐式类型,即使实际上是同一个数组。如果两个函数使用some,并且其协议或隐式类型不同,则不能将一个函数的结果用作另一个函数的参数。
在项目中,一切都通过any Protocol返回,集合失去类型化,出现类型转换问题,编译时优化变慢。
优点:
缺点:
在SwiftUI设计中,组件返回some View,每个模块清楚地定义内部类型。包的大小减少,构建速度加快。
优点:
缺点: