前言介绍
Swift中已经有some和any两个关键字用于配合协议使用,来约束使用者的类型必须符合协议
some
some关键字是在Swift5.1中引入,用于配合协议使用,创建不透明类型。在编译器看来,传入的参数依然是具体的类型,编译器使用了一个唯一的隐式类型接收这个类型,只不过编译器保证这个类型是遵循了这个协议的。它和使用泛型约束语法没任何区别
所以以下三种代码是等价的
// 使用简短泛型语法,约束T遵守协议
func wash<T: Vehicle>(_ vehicle: T) {}
// 使用完整泛型语法,约束T遵守协议
func wash<T>(_ vehicle: T) where T: Vehicle {}
// 使用some关键字,约束 匿名的不透明类型 遵守协议
// 因为这个类型在编译器看来和普通泛型类型的实参没任何区别。所以叫不透明类型
func wash(_ vehicle: some Vehicle) {}
some关键字可以用于函数参数、变量类型、类型修饰、函数返回值等
// 函数参数使用some
func funcUseSome(_ v: some Vehicle) {}
// 变量使用some
let varUseSome: some Vehicle = Car()
// 函数返回值类型使用some
func createSomeVehicle() -> some Vehicle {
return Car()
}
// 数组使用some
let arrUseSome: [some Vehicle] = []
不透明类型表示的隐式类型每次都是唯一的。下面的代码,一旦car变量就是一个隐式的不透明类型。
即使第二行代码又给car赋值了Car实例,这个Car类型也和上面生成的不透明类型不一样,会报错
var car: some Vehicle = Car()
// Cannot assign value of type 'Car' to type 'some Vehicle'
car = Car()
any
any是Swift5.6引入的,也是配合协议使用。它和some不同的是,它会将类型包装成existantial container。并且针对值类型和引用类型分别包装成不同容器类型
let myCar: any Vehicle = Car()
func wash(_ vehicle: any Vehicle) {}
any不会和some一样生成不透明的唯一类型,它最终就是Container类型,可以重复的赋值,只要符合协议就行
var myCar: any Vehicle = Car()
// 这里还可以继续赋值
myCar = Bus()
myCar = Car()
// 函数的if分支里,只要是符合协议的类型,都可以返回
func createAnyVehicle(isPublicTransport: Bool) -> any Vehicle {
if isPublicTransport {
return Bus()
} else {
return Car()
}
}
param pack
some 可以在保证在编译期就知道具体的类型,效率高。但它无法在集合中存放不同的符合协议的类型
any 把所有类型包装成existential container,极大的提高了灵活性,但同时也降低了效率
param pack 在Swift5.9引入,可以看作是对some的增强。这样我们在写接收不确定数量的泛型的函数时,就不用写多个重载函数了,用一个就可以搞定
没有param pack之前, 我们如果要支持元组的比较,要写N多个重载函数
一个应用实例
假设存在一个协议,能够生成任意类型的值。我们拥有多个可能产出数值或引发错误的生产者,目标是收集所有成功生成的值,并自动过滤掉错误情况。借助 param pack 特性,只需编写一个函数即可处理。在 Swift 6.0 中,param pack 支持 for in 循环,使得代码结构更加简洁直观。使用时,只需按照特定语法调用即可实现批量处理,极大简化了代码逻辑。
参考资料
func == (lhs: (), rhs: ()) -> Bool
func == <A, B>(lhs: (A, B), rhs: (A, B)) -> Bool where A: Equatable, B: Equatable
func == <A, B, C>(lhs: (A, B, C), rhs: (A, B, C)) -> Bool where A: Equatable, B: Equatable, C: Equatable
// and so on, up to 6-element tuples
// 使用 each Element引入不同的泛型形参
func == Element: Equatable>(lhs: (repeat each Element),
rhs: (repeat each Element)) -> Bool {
// 使用repeat each Element重复不同数量的泛型形参
// 编译器会保证lhs和rhs中泛型形参的数量是相等的
for (left, right) in repeat (each lhs, each rhs) {
guard left == right else { return false }
}
return true
}
protocol ValueProducer {
associatedtype Value: Codable
func evaluate() -> Value
}
func evaluateAllV: ValueProducer, each E: Error>(result: repeat ResultV, each E>) -> [any Codable] {
var evaluated: [any Codable] = []
for case .success(let valueProducer) in repeat each result {
evaluated.append(valueProducer.evaluate())
}
return evaluated
}
// 产生整数类型的值
struct IntProducer: ValueProducer {
let contained: Int
init(_ contained: Int) {
self.contained = contained
}
func evaluate() -> Int {
return self.contained
}
}
// 产生bool类型的值
struct BoolProducer: ValueProducer {
let contained: Bool
init(_ contained: Bool) {
self.contained = contained
}
func evaluate() -> Bool {
return self.contained
}
}
struct SomeError: Error {}
print(evaluateAll(result:
Result<SomeValueProducer,SomeError>.success(SomeValueProducer(5)),
Result<SomeValueProducer, SomeError>.failure(SomeError()),
Result<BoolProducer, SomeError>.success(BoolProducer(true))))
// [5, true]










