Swift存在类型any
Swift存在类型any

Swift存在类型any

any 关键字用于显式地标注协议类型,让代码更清晰并减少对协议类型(existential types)的混淆。

any历史

1、引入any之前

在 Swift 5.6 及更早的版本中,把协议当作类型使用(如 Decoder、Hashable):

Result<Int, Error>
let e: Error
func foo(_ e: Error)

这三种写法表示,一个遵循Error的未知具体类型(存在类型)。

2、引入any之后

从 Swift 5.7 开始引入 any,用于显式区分存在类型或者泛型约束。

这表示协议不再属于默认存在类型,使用协议作为类型需要显式写 any。

s: Shape    // 遵循 Shape 协议
s: any Shape    // Shape 类型的值

如果使用一个协议类型的值,需要加上 any,如 any Decoder,这是合法且推荐的写法。

不加 any,Swift 会假定泛型约束(或具体类型)。

3、兼容旧代码

目前,Swift 5.7+ 版本中,仍然存在两种写法:

Result<Int, Error>      // 兼容旧语法,语义 = any Error
Result<Int, any Error>  // 新语法,语义明确

在行为上是等价的,但是语义表达上不等价。

1)协议和类型混用是历史遗留问题,Swift为了兼容旧代码,仍然可以使用协议作为类型使用。

2)使用any标注存在类型,是新语法。官方文档和新API已全面使用 any Error。

但是在某些上下文中,编译器会提示:

Use of protocol ‘Error’ as a type must be written ‘any Error’

这是一种向后兼容+向前引导的策略。

any 用途

1、显式声明存在类型

使用 any,表示这是一个存在类型。

func f(_ e: any Error)    // 明确是存在类型

e 可以是任何符合 Error 协议的类型。

2、泛型约束

使用泛型约束(如 T: Protocol)时,编译器会优化为特定的具体类型。

func f<T: Error>(_ e: T)   // 泛型约束

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 是合适的。

如果性能敏感,且类型已知,建议使用泛型。

注意事项

1、协议不能实例化

any可以将协议作为存在类型,但是不能实例化:

protocol Animal {
    var sound: String { get }
}

let a: any Animal = Dog()
print(a.sound)

any Animal 是一个类型,可以作为变量类型、参数类型、数组类型,可以在运行期间装不同具体的实现(Dog / Cat)。

但是协议无法实例化:

let a = Animal()    // 协议不是构造器

协议没有存储结构、初始化方法和具体实现,所以无法创建实例。

总结

any 的核心作用:让协议类型的语义更加清晰。

当需要处理符合协议的值,而不是具体类型,使用 any。

当性能敏感,或者类型在编译时已知时,使用泛型或具体类型更高效。

相关文章

1、Swift不透明类型some

   

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开发者。

欢迎加入我们的 微信交流群QQ交流群,交流更多精彩内容!
微信交流群二维码 QQ交流群二维码

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注