身份运算符还可以检查命名类型是否相同,而不仅仅是引用相等
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
个操作数——大概是为了帮助互操作性)。
据我了解,恒等运算符用于判断两个对象是否具有相同的引用。这意味着,在实践中,运算符的两边应该是一个对象。
但是,我尝试了下面的代码,它让我对我所理解的恒等运算符的功能感到困惑
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.
的单数 ClassThe 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
个操作数——大概是为了帮助互操作性)。