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

问题描述 投票:0回答:3

当我尝试扩展像

(Int, Int)
Any
这样的非正统“类型”时,我会看到此错误:

非标称类型“Any”无法扩展

那么什么使类型成为非名义类型呢?

Any
(Int)
等非名义类型与
Int
等常规名义类型有什么区别?

swift
3个回答
127
投票

当前接受的答案不正确;实际的答案来自 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>
以使其更清楚,但现在他们正在努力保持源稳定性,这种情况不太可能发生。)


2
投票

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

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

因此您无法扩展

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


更新:

当然,您可以扩展协议。

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


0
投票

[Swift 类型]

非标称类型“Pair”(又名“

(key: String, value: String)
”)无法扩展

Swift 有两种类型的操作:

  1. named type
    nominal type
    type with name
    类似:
    • class
    • structure
    • enumeration
    • protocol
  2. 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
代替

© www.soinside.com 2019 - 2024. All rights reserved.