В Swift, кажется, есть два оператора равенства: двойное равенство ( ==
) и тройное равенство ( ===
), в чем разница между ними?
Коротко:
==
оператор проверяет, равны ли их значения экземпляра, "equal to"
===
оператор проверяет, указывают ли ссылки на один и тот же экземпляр, "identical to"
Длинный ответ:
Классы являются ссылочными типами, несколько констант и переменных могут ссылаться на один и тот же экземпляр класса за кулисами. Ссылки на классы остаются в стеке времени выполнения (RTS), а их экземпляры остаются в области кучи памяти. Когда вы контролируете равенство с ==
ним, значит, если их экземпляры равны друг другу. Это не должен быть один и тот же экземпляр, чтобы быть равным. Для этого вам нужно предоставить критерии равенства для вашего пользовательского класса. По умолчанию пользовательские классы и структуры не получают реализацию операторов эквивалентности по умолчанию, известную как оператор «равно» и оператор ==
«не равно» !=
. Для этого ваш пользовательский класс должен соответствовать Equatable
протоколу и его static func == (lhs:, rhs:) -> Bool
функциям.
Давайте посмотрим на пример:
class Person : Equatable {
let ssn: Int
let name: String
init(ssn: Int, name: String) {
self.ssn = ssn
self.name = name
}
static func == (lhs: Person, rhs: Person) -> Bool {
return lhs.ssn == rhs.ssn
}
}
P.S.:
Поскольку ssn (номер социального страхования) является уникальным номером, вам не нужно сравнивать, совпадают ли их имена или нет.
let person1 = Person(ssn: 5, name: "Bob")
let person2 = Person(ssn: 5, name: "Bob")
if person1 == person2 {
print("the two instances are equal!")
}
Хотя ссылки person1 и person2 указывают на два разных экземпляра в области кучи, их экземпляры равны, потому что их номера ssn равны. Таким образом, выход будетthe two instance are equal!
if person1 === person2 {
//It does not enter here
} else {
print("the two instances are not identical!")
}
===
Оператор проверяет, указывают ли ссылки на один и тот же экземпляр "identical to"
. Так как person1 и person2 имеют два разных экземпляра в области кучи, они не идентичны, и результатthe two instance are not identical!
let person3 = person1
P.S:
Классы являются ссылочными типами, и ссылка person1 копируется в person3 с помощью этой операции присваивания, поэтому обе ссылки указывают на один и тот же экземпляр в области кучи.
if person3 === person1 {
print("the two instances are identical!")
}
Они идентичны и на выходе будут the two instances are identical!
!==
и ===
являются идентичными операторами и используются для определения, имеют ли два объекта одинаковые ссылки.
Swift также предоставляет два идентификатора оператора (=== и! ==), которые вы используете, чтобы проверить, ссылаются ли обе ссылки на один и тот же экземпляр объекта.
Выдержка из: Apple Inc. «Язык программирования Swift». интерактивные книги. https://itun.es/us/jEUH0.l
==
естьisEqual:
или определенная классом семантическая эквивалентность.===
в Swift есть==
в (Obj) C - равенство указателей или идентичность объекта.var
илиlet
) имени к значению является уникальной копией, поэтому создавать указатели бессмысленно, поскольку значение, на которое вы указали, является значением, отличным от того, которое вы создали в первый раз. Другое заключается в том, что определение семантики значений в Swift абстрагирует хранилище - компилятор может свободно оптимизировать, вплоть до того, что он никогда не сохранит ваше значение в ячейке памяти, доступной за строкой, в которой он используется (регистр, кодирование инструкций и т. Д.).В обоих Objective-C и Свифта, то
==
и!=
тест операторы для значения равенства числовых значений (например,NSInteger
,NSUInteger
,int
, в Objective-C иInt
,UInt
и т.д. в Swift). Для объектов (NSObject / NSNumber и подклассов в Objective-C и ссылочных типов в Swift)==
и!=
проверьте, что объекты / ссылочные типы - это одно и то же, то есть одно и то же хеш-значение, или не одно и то же, соответственно ,Операторы равенства тождества Свифта
===
и!==
, проверяющие ссылочное равенство - и, таким образом, вероятно, должны называться операторами ссылочного равенства ИМО.Стоит также отметить, что пользовательские ссылочные типы в Swift (которые не подклассируют класс, который соответствует Equatable) не реализуют автоматически операторы равенства , но операторы равенства идентичности по- прежнему применяются. Также, путем реализации
==
,!=
автоматически реализуется.Эти операторы равенства не реализованы для других типов, таких как структуры на любом языке. Однако пользовательские операторы могут быть созданы в Swift, что, например, позволит вам создать оператор для проверки равенства CGPoint.
источник
==
не проверяет наNSNumber
равенство в Objective-C.NSNumber
этоNSObject
так тестирует на личность. Причина, по которой он работает SOMETIMES, заключается в том, что теги-указатели / кэшированные литералы объектов. Это не удастся для достаточно больших чисел и на 32-битных устройствах при сравнении не-литералов.Свифт 3 и выше
===
(или!==
)==
в Obj-C (равенство указателей).==
(или!=
)isEqual:
в поведении Obj-C.Здесь я сравниваю три экземпляра (класс является ссылочным типом)
источник
isEqual:
в Swift:override func isEqual(_ object: Any?) -> Bool {}
У Swifts есть тонкости,
===
которые выходят за рамки простой арифметики указателей. В то время как в Objective-C вы могли сравнивать любые два указателя (то естьNSObject *
) с==
этим больше не верно в Swift, так как типы играют гораздо большую роль во время компиляции.Детская площадка даст вам
Со строками нам придется привыкнуть к этому:
но тогда вы также можете повеселиться следующим образом:
Я уверен, что вы можете подумать о гораздо более забавных случаях :-)
Обновление для Swift 3 (согласно предложению Якуба Трухларжа)
Это выглядит немного более согласуется с
Type 'Int' does not conform to protocol 'AnyObject'
, однако мы тогда получимно явное преобразование проясняет, что может быть что-то происходит. На стороне String все
NSString
еще будет доступно, пока мыimport Cocoa
. Тогда у нас будетЭто по - прежнему запутанным иметь два класса String, но сбросив неявное преобразование, вероятно , сделать его немного более ощутимым.
источник
===
оператор для сравненияInts
. Не в Swift 3.===
не имеет смысла для структур, поскольку они являются типами значений. В частности, нужно помнить о трех типах: литеральные типы, такие как 1 или «foo», которые не привязаны к переменной и обычно влияют только на компиляцию, так как вы обычно не работаете с ними во время выполнения; Типы struct, такие какInt
иString
которые вы получаете при назначении литерала переменной, и классы, такие какAnyObject
иNSString
.Например, если вы создаете два экземпляра класса, например
myClass
:Вы можете сравнить эти случаи,
цитируется:
Выдержка из: Apple Inc. «Язык программирования Swift». интерактивные книги. https://itun.es/sk/jEUH0.l
источник
В Swift у нас есть === simbol, что означает, что оба объекта ссылаются на один и тот же ссылочный адрес
источник
Просто незначительный вклад, связанный с
Any
объектом.Я работал с модульными тестами
NotificationCenter
, которые используютAny
в качестве параметра, который я хотел сравнить на равенство.Однако, поскольку
Any
нельзя использовать в операции равенства, необходимо было ее изменить. В конечном итоге я остановился на следующем подходе, который позволил мне добиться равенства в моей конкретной ситуации, показанной здесь на упрощенном примере:Эта функция использует ObjectIdentifier , который предоставляет уникальный адрес для объекта, что позволяет мне тестировать.
Один пункт, чтобы отметить, хотя о
ObjectIdentifier
в Apple по ссылке выше:источник
==
используется для проверки , если две переменные равны т2 == 2
. Но в случае===
этого означает равенство, т.е. если два экземпляра ссылаются на один и тот же пример объекта в случае классов, создается ссылка, которая содержится во многих других экземплярах.источник
Swift 4: еще один пример использования модульных тестов, который работает только с ===
Примечание: Тест ниже не проходит с ==, работает с ===
И класс существо
Ошибка в модульных тестах, если вы используете ==,
Binary operator '==' cannot be applied to operands of type 'UITextFieldDelegate?' and 'ViewControllerUnderTest!'
источник