Разница между использованием ObjectIdentifier() и оператора ===

Допустим, я реализую корневой класс в Swift, который я объявляю, принимает 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():

Уникальный идентификатор экземпляра класса или метатипа. В Swift только экземпляры классов и метатипы имеют уникальные идентификаторы. Не существует понятия идентичности для структур, перечислений, функций или кортежей.

... и это то, что в разделе "Основные операторы" языка программирования Swift (Swift 3) говорится о === оператор:

НОТА

Swift также предоставляет два идентификатора оператора (=== а также !==), который вы используете, чтобы проверить, ссылаются ли обе ссылки на один и тот же экземпляр объекта. Для получения дополнительной информации см. Классы и структуры.

1 ответ

Решение

Для экземпляра класса нет никакой разницы, см. Следующие комментарии в 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"
  ///

Это также становится очевидным из реализации == за ObjectIdentifier, который просто сравнивает указатели с хранилищем объекта:

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

что то, что === Оператор также делает:

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, так что это полезно, если вы хотите реализовать этот протокол для вашего класса:

extension MyClass: Hashable {
    var hashValue: Int {
        return ObjectIdentifier(self).hashValue
    }
}

Идентификатор объекта также может быть создан для мета-типов (например, ObjectIdentifier(Float.self)) для которого === не определено.

Другие вопросы по тегам