当我尝试扩展像
(Int, Int)
或Any
这样的非正统“类型”时,我会看到此错误:
非标称类型“Any”无法扩展
那么什么使类型成为非名义类型呢?
Any
或 (Int)
等非名义类型与 Int
等常规名义类型有什么区别?
当前接受的答案不正确;实际的答案来自 Swift 类型系统深奥的部分。
Swift 中的大多数类型都是名义类型——它们是在特定模块中作为用户代码的一部分声明的“命名”类型。像
Int
和 Array
这样看似原始的类型实际上是在 Swift
模块中定义的结构,该模块会自动导入到每个 Swift 源文件中。即使 Optional
本身也是 Swift
模块中的枚举,尽管编译器添加了一些魔法,例如可选链接和强制展开。
少数例外称为“非名义类型”。可能还有其他,但主要的是:
(Int) -> String
(Int, String)
String.Type
(表达式的类型 String.self
)CustomStringConvertible & Error
存在主义值得更多解释。存在性包含一个值,该值的确切类型已被抽象掉,但已知该值符合一组特定的协议。例如:
// You can put anything that conforms to `CustomStringConvertible` in `x`
let x: CustomStringConvertible
// You can put anything that conforms to both `CustomStringConvertible`
// and `Error` in `y`
let y: CustomStringConvertible & Error
// You can put anything in `z`; `Any` is an existential that doesn't
// require you to conform to any particular protocols
let z: Any
非名义类型都只是以某种特殊的方式将其他类型组合在一起。 (它们有时被称为“结构类型”,因为它们定义了某种通用结构,供其他类型插入。)它们不需要显式定义,并且它们不属于任何特定模块 - FooKit 的
(Int, String)
与 BarKit 的 (Int, String)
相同。但它们的所有行为都是由语言定义的——非名义类型不能有自己的方法或属性,不能符合协议,因此不能扩展。
所以你不能扩展
Any
,因为Any
是语言中内置的一个特殊的东西,就像函数类型或元组类型一样。它只是碰巧有一个用字母写的名字,而不是标点符号。
(那么为什么你可以扩展
CustomStringConvertible
?因为,根据上下文,CustomStringConvertible
可能意味着协议,或者可能意味着包含符合协议的值的存在。当你写下extension CustomStringConvertible
时,你正在扩展协议,但是当您编写 let x: CustomStringConvertible
时,您声明了一个类型为“存在且包含符合协议的值”的变量,这有点令人困惑,而且 Swift 的一些维护者实际上希望需要 require 。存在主义被写成 Any<CustomStringConvertible>
以使其更清楚,但现在他们正在努力保持源稳定性,这种情况不太可能发生。)
非标称类型“Pair”(又名“
”)无法扩展(key: String, value: String)
Swift 有两种类型的操作:
named type
或 nominal type
或 type with name
类似:
class
structure
enumeration
protocol
compound type
或 non-nominal type
或 type without name
类似:
function
tuple
当使用
extends
复合类型时会出现此错误。例如
public typealias Pair = (key: String, value: String)
public extension Pair { //compile time error
}
作为使用
extends
功能的变体,您可以使用 named type
代替