据我所知,身份运算符用于确定两个对象是否具有相同的引用。实际上,这意味着操作员的双方都应该是一个对象。
但是,我尝试了下面的代码,它让我对身份运算符的功能感到困惑
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"
}
身份运算符的左侧和右侧不是对象而是类型,对于这一点,似乎语义等价运算符和对象标识运算符(看起来像)以相同的方式工作。
问题:
这是一个错误还是我没有正确理解这一点。
感谢您的帮助和时间
答案 0 :(得分:1)
不是错误,它们是相同的。
狗,作为一个类(类型)是一个单数,只能有一个。可以有许多实例但只有一个类。type(of:d)返回d的所有者类,Dog.self返回Class本身。它们是完全相同的对象,单一的狗类。
答案 1 :(得分:1)
身份运算符的左侧和右侧不是对象而是类型。
实际上,在Apple平台上,他们是对象。
这是因为Swift类在幕后实现为Objective-C类,正如Mike Ash详细介绍in this great blog post。这意味着类的元类型也是一个Objective-C类,因此符合AnyObject
。
因此,您可以将类元类型与标识运算符进行比较,因为它定义为:
public func ===(lhs: AnyObject?, rhs: AnyObject?) -> Bool
它将比较两个对象是否是同一个对象,或者特别是在这种情况下,是相同的类元类型。
相反,在幕后,值类型的元类型不是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
。实际上,使用标识运算符来比较类元类型的能力只是它们被实现为Objective-C对象的副作用。
比较元类型的通用方法是使用等于运算符==
,因为Swift专门为元类型提供了一个重载:
public func ==(t0: Any.Type?, t1: Any.Type?) -> Bool
这会检查两个元类型是否相同,但与===
不同,它适用于类类元类型和值类型元类型。在引擎盖下,它实现了as a simple pointer comparison,所以应始终产生与===
类相同的结果。
因此,我始终建议将元类型与==
进行比较,因为您不依赖于AnyObject
的一致性。例如,在Linux平台上,class metatypes don't conform to AnyObject
因此无法与身份运算符进行比较(尽管有趣的是,导入Foundation
时,似乎为{{1}添加了===
重载操作数 - 可能是为了辅助互操作性。)