使用 ObjectIdentifier() 和 '===' 运算符的区别

Difference between using ObjectIdentifier() and '===' Operator

假设我在 Swift 中实现一个根 class,我声明它采用 Equatable 协议(我希望能够判断我的类型的数组是否是否包含给定实例)。

有什么区别 - 如果有的话,在这种特定情况下 - 在实施协议所需的 == 运算符之间有什么区别:

public static func ==(lhs: MyClass, rhs: MyClass) -> Bool {

    return ObjectIdentifier(lhs) == ObjectIdentifier(rhs)
}

...而不是仅仅这样做:

public static func ==(lhs: MyClass, rhs: MyClass) -> Bool {

    return (lhs === rhs)
}

作为参考,这是文档中关于 ObjectIdentifier() 的内容:

A unique identifier for a class instance or metatype. In Swift, only class instances and metatypes have unique identities. There is no notion of identity for structs, enums, functions, or tuples.

...这就是 The Swift Programming Language (Swift 3) 的 "Basic Operators" 部分关于 === 运算符的内容:

NOTE

Swift also provides two identity operators (=== and !==), which you use to test whether two object references both refer to the same object instance. For more information, see Classes and Structures.

class实例没有区别,见下文 comments in ObjectIdentifier.swift:

  /// Creates an instance that uniquely identifies the given class instance.
  ///
  /// The following example creates an example class `A` and compares instances
  /// of the class using their object identifiers and the identical-to
  /// operator (`===`):
  ///
  ///     class IntegerRef {
  ///         let value: Int
  ///         init(_ value: Int) {
  ///             self.value = value
  ///         }
  ///     }
  ///
  ///     let x = IntegerRef(10)
  ///     let y = x
  ///
  ///     print(ObjectIdentifier(x) == ObjectIdentifier(y))
  ///     // Prints "true"
  ///     print(x === y)
  ///     // Prints "true"
  ///
  ///     let z = IntegerRef(10)
  ///     print(ObjectIdentifier(x) == ObjectIdentifier(z))
  ///     // Prints "false"
  ///     print(x === z)
  ///     // Prints "false"
  ///

implementation of == for ObjectIdentifier, 它只是比较指向对象存储的指针:

  public static func == (x: ObjectIdentifier, y: ObjectIdentifier) -> Bool {
    return Bool(Builtin.cmp_eq_RawPointer(x._value, y._value))
  }

这就是 the === operator 也一样:

public func === (lhs: AnyObject?, rhs: AnyObject?) -> Bool {
  switch (lhs, rhs) {
  case let (l?, r?):
    return Bool(Builtin.cmp_eq_RawPointer(
        Builtin.bridgeToRawPointer(Builtin.castToUnknownObject(l)),
        Builtin.bridgeToRawPointer(Builtin.castToUnknownObject(r))
      ))
  case (nil, nil):
    return true
  default:
    return false
  }
}

ObjectIdentifier 符合 Hashable,因此如果您想为您的 class:

实现该协议,它会很有用
extension MyClass: Hashable {
    var hashValue: Int {
        return ObjectIdentifier(self).hashValue
    }
}

也可以为元类型创建对象标识符 (例如 ObjectIdentifier(Float.self))未定义 ===