在 Swift 中,any 是一个 关键字,用于显式地标注 协议类型。它是在 Swift 5.7 中引入的,目的是让代码更清晰并减少对协议类型(existential types)的混淆。
any 的核心作用是区分以下两种情况:
1、协议类型作为值(any Protocol)。
2、协议类型作为泛型约束(不需要 any 关键字)。
为什么需要 any?
在引入 any 之前,直接写协议类型(如 Decoder、Hashable)实际上表示了一个 existential type(协议存在类型),但这一点并不明显,容易导致代码语义模糊。
例如:
let decoder: Decoder:这指的是一个协议值。
let decoder: some Decoder:这是一个符合 Decoder 协议的具体类型(泛型)。
func process<T: Decoder>(_ decoder: T):这是一个泛型函数,使用泛型约束。
Swift 团队引入 any 来明确区分协议类型和泛型约束:
如果你明确想使用一个 协议类型的值,需要加上 any,如 any Decoder。
如果不加 any,Swift 会假定你想用泛型约束(或具体类型)。
any 的用途
1、显式声明协议类型
使用 any,表示这是一个协议类型的值,而不是某个具体的实现类型。
示例:
let value: any Hashable // 一个符合 Hashable 协议的值,不限具体类型
在这里,value 可以是任何符合 Hashable 协议的类型(如 Int、String 等)。
2、与泛型约束对比
使用泛型约束(如 T: Protocol)时,编译器会优化为特定的具体类型。
而 any 是运行时存在的协议值,性能略低。
示例对比:
func printValue<T: Hashable>(_ value: T) {
print(value)
}
泛型函数 printValue 是在编译时决定 T 的具体类型(例如 Int 或 String)。
func printValue(_ value: any Hashable) {
print(value)
}
此函数接受 任何类型的值,只要它符合 Hashable 协议。
3、在函数参数中使用
如果一个参数需要接受协议类型作为值,可以显式地使用 any:
func performAction(with value: any Decodable) {
// 处理符合 Decodable 的值
}
4、在属性或变量中使用
当属性需要存储一个协议类型的值时,any 可以明确类型语义:
var items: [any Hashable] = [1, "Hello", 3.14]
在这个例子中,items 数组可以存储任意符合 Hashable 的值。
any 的特点
1、性能区别
使用 any 时,Swift 会将协议类型的值存储在一个 existential container 中,包含类型信息和方法表。这种方式会有一定的性能开销。
使用泛型时,编译器会在编译期优化为具体类型,因此性能更高。
2、语法清晰
使用 any 明确指出一个值是协议类型,而不是泛型。
3、适用场景
当你需要运行时存储、传递协议类型的值时(例如多态场景),使用 any 是合适的。
如果性能敏感,且类型已知,建议使用泛型。
示例代码
以下代码演示了如何使用 any 和泛型:
protocol Shape {
func draw()
}
struct Circle: Shape {
func draw() {
print("Drawing a circle")
}
}
struct Square: Shape {
func draw() {
print("Drawing a square")
}
}
// 使用 `any Shape` (协议类型)
let shapes: [any Shape] = [Circle(), Square()]
for shape in shapes {
shape.draw()
}
// 使用泛型 (编译时确定类型)
func drawShape<T: Shape>(_ shape: T) {
shape.draw()
}
drawShape(Circle())
drawShape(Square())
总结
any 的核心作用:让协议类型的语义更加清晰。
何时使用 any:
当你需要处理符合协议的值,而不是具体类型。
当你需要多态或运行时存储协议类型的值。
何时不使用 any:
当性能敏感,或者类型在编译时已知时,使用泛型或具体类型更高效。