什么是Swift中的"非名义类型"?

Jos*_*ark 29 swift

我试图扩展非正统的'类型'时看到这个错误(Int, Int),或者Any:

非名义类型"任何"不能扩展

那么什么使一种类型非名义?什么是一个非标称型等之间的差异Any(Int)和常规标称型样Int

Bre*_*don 70

目前接受的答案是不正确; 实际的答案来自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
Run Code Online (Sandbox Code Playgroud)

非名义类型都只是以某种特殊的方式将其他类型组合在一起.(它们有时被称为"结构类型",因为它们为其他类型定义某种通用结构以插入.)它们不需要显式定义,并且它们不属于任何特定模块 - FooKit (Int, String)是和BarKit一样(Int, String).但是它们的所有行为都是由语言定义的 - 非名义类型不能拥有自己的方法或属性,不能符合协议,因此无法扩展.

因此,您无法扩展,Any因为它Any是一种内置于语言中的特殊内容,就像函数类型或元组类型一样.它碰巧有一个用字母写的名字,而不是用标点符号.

(那么为什么你可以扩展CustomStringConvertible?因为,根据上下文,CustomStringConvertible可能意味着协议或它可能意味着包含符合协议的值存在性.当你写extension CustomStringConvertible,你扩展协议,但是当你写let x: CustomStringConvertible,你是声明一个变量,其类型为"存在性,包含符合协议的值".这有点令人困惑,Swift的一些维护者实际上希望要求存在性写入Any<CustomStringConvertible>以使其更清晰.不太可能发生但是现在他们正试图保持源稳定性.)

  • @IslamQ.:更确切地说,Void是一个[`typealias`](https://github.com/apple/swift/blob/master/stdlib/public/core/Policy.swift#L53),用于空元组. (6认同)
  • “Void”是另一种非名义类型 (3认同)

Jia*_*aro 3

这有点猜测(编辑:这是错误的,看看布伦特的答案),但这里是:

Any是一个协议,而不是实际类型。“名义”一词意味着命名(基于词根)。

因此,您无法扩展,Any因为它是协议,而不是实际类型,并且您无法扩展(Int, Int),因为它只是一个元组文字,也不是您可以通过名称指定的实际类型。


更新:

当然,您可以扩展协议。Any不是一个协议,它是(令人震惊的)一种非名义类型,这是别的东西。阅读布伦特的回答;他做得很好。

  • `Any` 是一个空协议的 `typealias`,它的完整定义是 `typealias Any = protocol&lt;&gt;`。您可以通过以下方式组合协议:`typealias MyPrintableSeqance = protocol&lt;Printable, Sequence&gt;` 并将其用作协议 (4认同)
  • @sjeohp 我在操场上输入了 `var x: Any`,然后在“Any”上输入了 `&lt;cmd&gt; - clicked` - 该文件只是标题,但在类型别名的情况下,标题就是整个内容 (2认同)