身份运算符还可以检查命名类型是否相同,而不仅仅是引用相等

Identity operator can also check whether named types are the same rather only than reference equaliy

据我了解,恒等运算符用于判断两个对象是否具有相同的引用。这意味着,在实践中,运算符的两边应该是一个对象。

但是,我尝试了下面的代码,它让我对我所理解的恒等运算符的功能感到困惑

class Dog {}

let d: Dog = Dog()

if type(of: d) === Dog.self {
    print("yep") //prints out "yep"
}

if type(of: d) == Dog.self {
    print("yep") //prints out "yep"
}

恒等运算符的左右两边不是对象而是类型,在这一点上,语义等价运算符和对象恒等运算符(看起来)的工作方式似乎是一样的。

问题

这是一个错误还是我没有正确理解整个要点。

感谢您的帮助和时间

不是错误,它们是同一回事。

狗,因为class(类型)是单数,所以只能有一个。可以有很多实例,但只有 Class.

之一

type(of: d) return d 的所有者 Class,Dog.self returns Class 本身。它们是完全相同的对象,Dog.

的单数 Class

The left and right side of the identity operator is not an object but a type.

实际上,在 Apple 平台上,它们 个对象。

这是因为 Swift classes 在幕后被实现为 Objective-C classes,Mike Ash 详细介绍了 in this great blog post.这意味着 class 的元类型是 也是 和 Objective-C class,因此符合 AnyObject.

因此,您可以将 class 元类型与标识运算符进行比较,因为它定义为:

public func ===(lhs: AnyObject?, rhs: AnyObject?) -> Bool

它将比较两个对象是否是同一个对象,或者在这种情况下,具体来说,是相同的 class 元类型。

相反,在幕后,值类型的元类型不是Objective-C对象——它只是指向一些静态元数据的指针。如果我们重写您的示例以使用 struct:

struct Dog {}

let d = Dog()

// Binary operator '===' cannot be applied to two 'Dog.Type' operands
if type(of: d) === Dog.self {
    print("yep")
}

您会看到我们不能再使用 === 来比较元类型,因为它们不符合 AnyObject。所以实际上,使用恒等运算符比较 class 元类型的能力只是它们作为 Objective-C 对象实现的副作用。

比较元类型的通用方法是使用相等运算符==,因为Swift专门为元类型提供重载:

public func ==(t0: Any.Type?, t1: Any.Type?) -> Bool

这会检查两个元类型是否相同,但与 === 不同的是,它适用于 both class 元类型和值类型元类型。在引擎盖下,它实现了 as a simple pointer comparison,因此应该始终产生与 === 和 class 元类型相同的结果。

因此,我总是建议将元类型与 == 进行比较,因为您不依赖于 AnyObject 的一致性。例如,在 Linux 平台上, class metatypes don't conform to AnyObject 因此不能与身份运算符进行比较(尽管有趣的是,当导入 Foundation 时,它似乎添加了 === 重载对于 AnyObject.Type 个操作数——大概是为了帮助互操作性)。