W trybie szybkim wydaje się, że istnieją dwa operatory równości: podwójny równa się ( ==
) i potrójny równa się ( ===
), jaka jest różnica między tymi dwoma?
W skrócie:
==
operator sprawdza, czy wartości ich instancji są równe, "equal to"
===
operator sprawdza, czy odniesienia wskazują tę samą instancję, "identical to"
Długa odpowiedź:
Klasy są typami referencyjnymi, wiele stałych i zmiennych może odnosić się do tego samego pojedynczego wystąpienia klasy za scenami. Odwołania do klas pozostają w stosie czasu wykonywania (RTS), a ich instancje pozostają w obszarze sterty pamięci. Kiedy kontrolujesz równość ==
, oznacza to, czy ich instancje są sobie równe. Nie musi to być ta sama instancja, aby być równym. W tym celu musisz podać kryteria równości dla swojej klasy niestandardowej. Domyślnie niestandardowe klasy i struktury nie otrzymują domyślnej implementacji operatorów równoważności, znanych jako operator „równy” ==
i operator „nie równy” !=
. Aby to zrobić, twoja klasa niestandardowa musi być zgodna z Equatable
protokołem i jego static func == (lhs:, rhs:) -> Bool
funkcją
Spójrzmy na przykład:
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.:
Ponieważ ssn (numer ubezpieczenia społecznego) jest unikalnym numerem, nie trzeba porównywać, czy ich nazwa jest równa czy nie.
let person1 = Person(ssn: 5, name: "Bob")
let person2 = Person(ssn: 5, name: "Bob")
if person1 == person2 {
print("the two instances are equal!")
}
Chociaż odniesienia person1 i person2 wskazują dwa różne wystąpienia w obszarze sterty, ich wystąpienia są równe, ponieważ ich liczby ssn są równe. Więc wynik będziethe two instance are equal!
if person1 === person2 {
//It does not enter here
} else {
print("the two instances are not identical!")
}
===
Kontrola operatora w przypadku odniesienia wskazują ten sam przykład, "identical to"
. Ponieważ person1 i person2 mają dwie różne instancje w obszarze sterty, nie są one identyczne i dane wyjściowethe two instance are not identical!
let person3 = person1
P.S:
Klasy są typami referencji, a referencja osoby1 jest kopiowana do osoby3 za pomocą tej operacji przypisania, dlatego oba odniesienia wskazują tę samą instancję w obszarze Sterty.
if person3 === person1 {
print("the two instances are identical!")
}
Są identyczne, a wynik będzie the two instances are identical!
!==
i ===
są operatorami tożsamości i służą do ustalenia, czy dwa obiekty mają to samo odniesienie.
Swift udostępnia również dwa operatory tożsamości (=== i! ==), których używasz do testowania, czy dwa odwołania do obiektów odnoszą się do tej samej instancji obiektu.
Fragment: Apple Inc. „Swift Programming Language”. iBooks. https://itun.es/us/jEUH0.l
==
jestisEqual:
lub semantyczna równoważność zdefiniowana przez klasę.===
w Swift jest==
w (Obj) C - równość wskaźnika lub tożsamość obiektu.var
lublet
) nazwy z wartością jest unikalną kopią - więc tworzenie wskaźników nie ma sensu, ponieważ wartość, na którą utworzyłeś wskaźnik, jest inną wartością niż ta, którą stworzyłeś po raz pierwszy. Innym jest to, że definicja semantyki wartości Swifta odciąga pamięć - kompilator może dowolnie optymalizować, aż do przechowywania wartości w miejscu dostępnym poza linią, w której jest używana (rejestr, kodowanie instrukcji itp.).Zarówno cel C i SWIFT,
==
a!=
testy operatorów równości wartości dla wartości liczbowych (na przykładNSInteger
,NSUInteger
,int
w celu C iInt
,UInt
itp Swift). W przypadku obiektów (NSObject / NSNumber i podklasy w Objective-C i typy referencyjne w Swift)==
i!=
przetestuj, czy obiekty / typy referencyjne są tą samą identyczną rzeczą - tj. Taką samą wartością skrótu - lub nie są odpowiednio identyczne .Operatory równości tożsamości Swifta
===
i!==
sprawdzenie równości referencyjnej - a zatem powinny być prawdopodobnie nazywane operatorami równości referencyjnej IMO.Warto również zauważyć, że niestandardowe typy referencyjne w Swift (które nie podklasują klasy zgodnej z Equatable) nie implementują automatycznie operatorów równości, ale operatory równości tożsamości nadal mają zastosowanie. Ponadto, poprzez wdrożenie
==
,!=
jest automatycznie realizowane.Te operatory równości nie są implementowane dla innych typów, takich jak struktury w obu językach. Jednak w Swift można tworzyć niestandardowe operatory, które umożliwiłyby na przykład utworzenie operatora sprawdzającego równość CGPoint.
źródło
==
nie sprawdzaNSNumber
równości w celu C.NSNumber
jestNSObject
więc testuje tożsamość. Powodem, dla którego SOMETIMES działa, są otagowane wskaźniki / literały obiektów buforowanych. Nie powiedzie się w przypadku wystarczająco dużych liczb i na urządzeniach 32-bitowych podczas porównywania literałów.W szybkim 3 i wyższym
===
(lub!==
)==
w Obj-C (równość wskaźnika).==
(lub!=
)isEqual:
zachowanie Obj-C.Tutaj porównuję trzy instancje (klasa jest typem referencyjnym)
źródło
isEqual:
w Swift:override func isEqual(_ object: Any?) -> Bool {}
W jerzykach są subtelności,
===
które wykraczają poza zwykłą arytmetykę wskaźników. Będąc w Objective-C mogłeś porównać dowolne dwa wskaźniki (tj.NSObject *
) Z==
tym nie jest już prawdą w Swift, ponieważ typy odgrywają znacznie większą rolę podczas kompilacji.Plac zabaw da ci
Z ciągami będziemy musieli się do tego przyzwyczaić:
ale możesz także bawić się w następujący sposób:
Jestem pewien, że możesz wymyślić o wiele zabawniejszych przypadków :-)
Aktualizacja dla Swift 3 (zgodnie z sugestią Jakuba Truhlářa)
Wygląda to nieco bardziej spójnie
Type 'Int' does not conform to protocol 'AnyObject'
, ale potem się pojawiaale wyraźna konwersja wyjaśnia, że coś może się dziać. Po stronie String rzeczy
NSString
będą dostępne tak długo, jak myimport Cocoa
. Wtedy będziemy mieliWciąż mylące są dwie klasy String, ale porzucenie niejawnej konwersji prawdopodobnie sprawi, że będzie ona nieco bardziej namacalna.
źródło
===
operatora do porównaniaInts
. Nie w Swift 3.===
nie ma znaczenia dla struktur, ponieważ są to typy wartości. W szczególności należy pamiętać o trzech typach: typach literalnych, takich jak 1 lub „foo”, które nie są powiązane ze zmienną i zwykle wpływają tylko na kompilację, ponieważ generalnie nie radzisz sobie z nimi podczas działania; typy struct takie jakInt
i,String
które otrzymujesz po przypisaniu literału zmiennej, oraz klasy takie jakAnyObject
iNSString
.Na przykład, jeśli utworzysz dwa wystąpienia klasy, np .
myClass
:możesz porównać te wystąpienia,
cytowane:
Fragment: Apple Inc. „Swift Programming Language”. iBooks. https://itun.es/sk/jEUH0.l
źródło
W Swift mamy simbol ===, co oznacza, że oba obiekty odnoszą się do tego samego odwołania tego samego adresu
źródło
Tylko niewielki wkład związany z
Any
obiektem.Pracowałem przy testach jednostkowych
NotificationCenter
, które wykorzystująAny
jako parametr, który chciałem porównać dla równości.Ponieważ jednak
Any
nie można go użyć w operacji równości, konieczna była jego zmiana. Ostatecznie zdecydowałem się na następujące podejście, które pozwoliło mi uzyskać równość w mojej konkretnej sytuacji, pokazanej tutaj na uproszczonym przykładzie:Ta funkcja korzysta z ObjectIdentifier , który zapewnia unikalny adres dla obiektu, umożliwiając mi testowanie.
Jedną rzecz wartą uwagi na temat
ObjectIdentifier
na Apple pod powyższym linkiem:źródło
==
służy do sprawdzenia, czy dwie zmienne są równe, tj2 == 2
. Ale w przypadku===
równości oznacza to, że w przypadku dwóch instancji odnoszących się do tego samego obiektu przykład w przypadku klas tworzone jest odwołanie, które jest przechowywane przez wiele innych instancji.źródło
Swift 4: Kolejny przykład użycia testów jednostkowych, który działa tylko z ===
Uwaga: test poniżej kończy się niepowodzeniem z ==, działa z ===
A klasa jest
Błąd w testach jednostkowych, jeśli użyjesz ==,
Binary operator '==' cannot be applied to operands of type 'UITextFieldDelegate?' and 'ViewControllerUnderTest!'
źródło