No Swift, parece haver dois operadores de igualdade: o dobro é igual a ( ==) e o triplo é igual a ===), qual é a diferença entre os dois?
No Swift, parece haver dois operadores de igualdade: o dobro é igual a ( ==) e o triplo é igual a ===), qual é a diferença entre os dois?
Respostas:
Em resumo:
== O operador verifica se seus valores de instância são iguais, "equal to"
=== O operador verifica se as referências apontam para a mesma instância, "identical to"
Resposta longa:
Classes são tipos de referência, é possível que várias constantes e variáveis se refiram à mesma instância única de uma classe nos bastidores. As referências de classe permanecem no RTS (Run Time Stack) e suas instâncias permanecem na área Heap da Memória. Quando você controla a igualdade ==, significa se as instâncias são iguais entre si. Não precisa ser a mesma instância para ser igual. Para isso, você precisa fornecer um critério de igualdade para sua classe personalizada. Por padrão, as classes e estruturas personalizadas não recebem uma implementação padrão dos operadores de equivalência, conhecidos como operador "igual a" ==e "não igual a" !=. Para fazer isso, sua classe personalizada precisa estar em conformidade com o Equatableprotocolo e sua static func == (lhs:, rhs:) -> Boolfunção
Vejamos o exemplo:
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.: Como ssn (número de segurança social) é um número único, você não precisa comparar se o nome deles é igual ou não.
let person1 = Person(ssn: 5, name: "Bob")
let person2 = Person(ssn: 5, name: "Bob")
if person1 == person2 {
print("the two instances are equal!")
}
Embora as referências person1 e person2 apontem duas instâncias diferentes na área Heap, suas instâncias são iguais porque seus números ssn são iguais. Então a saída seráthe two instance are equal!
if person1 === person2 {
//It does not enter here
} else {
print("the two instances are not identical!")
}
===O operador verifica se as referências apontam para a mesma instância "identical to",. Como person1 e person2 têm duas instâncias diferentes na área Heap, elas não são idênticas e a saídathe two instance are not identical!
let person3 = person1
P.S: Classes são tipos de referência e a referência de person1 é copiada para person3 com esta operação de atribuição, portanto, ambas as referências apontam a mesma instância na área Heap.
if person3 === person1 {
print("the two instances are identical!")
}
Eles são idênticos e a saída será the two instances are identical!
!==e ===são operadores de identidade e são usados para determinar se dois objetos têm a mesma referência.
O Swift também fornece dois operadores de identidade (=== e! ==), que você usa para testar se duas referências a objetos se referem à mesma instância de objeto.
Trecho de: Apple Inc. “A linguagem de programação Swift”. iBooks. https://itun.es/us/jEUH0.l
varou let) de um nome a um valor é uma cópia exclusiva - portanto, não faz sentido criar ponteiros porque o valor para o qual você fez um ponteiro é um valor diferente daquele que você criou primeiro. Outra é que a definição de semântica de valores de Swift abstrai o armazenamento - o compilador é livre para otimizar, inclusive incluindo nunca armazenar seu valor em um local de memória acessível além da linha em que é usado (registro, codificação de instruções etc.).
Em ambos Objectivo-C e Swift, a ==e !=teste de operadores para a igualdade valor para valores de número (por exemplo, NSInteger, NSUInteger, int, em Objective-C e Int, UInt, etc., em Swift). Para objectos (NSObject / NSNumber e subclasses em Objective-C e tipos de referência em Swift), ==e !=teste que os objetos / tipos de referência são a mesma coisa idêntica - ou seja, o mesmo valor de hash - ou não são a mesma coisa idêntica, respectivamente .
let a = NSObject()
let b = NSObject()
let c = a
a == b // false
a == c // true
Os operadores de igualdade de identidade de Swift ===e !==, verificam a igualdade referencial - e, portanto, provavelmente devem ser chamados de operadores de igualdade referencial IMO.
a === b // false
a === c // true
Também vale ressaltar que os tipos de referência personalizados no Swift (que não subclassificam uma classe que é compatível com Equatable) não implementam automaticamente o igual a operadores, mas os operadores de igualdade de identidade ainda se aplicam. Além disso, implementando ==, !=é implementado automaticamente.
class MyClass: Equatable {
let myProperty: String
init(s: String) {
myProperty = s
}
}
func ==(lhs: MyClass, rhs: MyClass) -> Bool {
return lhs.myProperty == rhs.myProperty
}
let myClass1 = MyClass(s: "Hello")
let myClass2 = MyClass(s: "Hello")
myClass1 == myClass2 // true
myClass1 != myClass2 // false
myClass1 === myClass2 // false
myClass1 !== myClass2 // true
Esses operadores de igualdade não são implementados para outros tipos, como estruturas em qualquer idioma. No entanto, operadores personalizados podem ser criados no Swift, o que, por exemplo, permitiria criar um operador para verificar a igualdade de um CGPoint.
infix operator <==> { precedence 130 }
func <==> (lhs: CGPoint, rhs: CGPoint) -> Bool {
return lhs.x == rhs.x && lhs.y == rhs.y
}
let point1 = CGPoint(x: 1.0, y: 1.0)
let point2 = CGPoint(x: 1.0, y: 1.0)
point1 <==> point2 // true
==não testa a NSNumberigualdade no Objective-C. NSNumberé um NSObjectteste para identidade. A razão pela qual SOMETIMES funciona é por causa de literais de ponteiros / objetos em cache marcados. Ele falhará em números grandes o suficiente e em dispositivos de 32 bits ao comparar não literais.
===(ou !==)==no Obj-C (igualdade de ponteiro).==(ou !=)isEqual:no comportamento Obj-C.Aqui eu comparo três instâncias (classe é um tipo de referência)
class Person {}
let person = Person()
let person2 = person
let person3 = Person()
person === person2 // true
person === person3 // false
isEqual:no Swift:override func isEqual(_ object: Any?) -> Bool {}
Existem sutilezas com Swifts ===que vão além da mera aritmética de ponteiros. Enquanto em Objective-C, você foi capaz de comparar dois ponteiros (ie NSObject *) com== isso não é mais verdade no Swift, pois os tipos desempenham um papel muito maior durante a compilação.
Um Playground lhe dará
1 === 2 // false
1 === 1 // true
let one = 1 // 1
1 === one // compile error: Type 'Int' does not conform to protocol 'AnyObject'
1 === (one as AnyObject) // true (surprisingly (to me at least))
Com as strings, teremos que nos acostumar com isso:
var st = "123" // "123"
var ns = (st as NSString) // "123"
st == ns // true, content equality
st === ns // compile error
ns === (st as NSString) // false, new struct
ns === (st as AnyObject) // false, new struct
(st as NSString) === (st as NSString) // false, new structs, bridging is not "free" (as in "lunch")
NSString(string:st) === NSString(string:st) // false, new structs
var st1 = NSString(string:st) // "123"
var st2 = st1 // "123"
st1 === st2 // true
var st3 = (st as NSString) // "123"
st1 === st3 // false
(st as AnyObject) === (st as AnyObject) // false
mas você também pode se divertir da seguinte maneira:
var st4 = st // "123"
st4 == st // true
st4 += "5" // "1235"
st4 == st // false, not quite a reference, copy on write semantics
Tenho certeza que você pode pensar em casos muito mais engraçados :-)
Atualização para o Swift 3 (conforme sugerido pelo comentário de Jakub Truhlář)
1===2 // Compiler error: binary operator '===' cannot be applied to two 'Int' operands
(1 as AnyObject) === (2 as AnyObject) // false
let two = 2
(2 as AnyObject) === (two as AnyObject) // false (rather unpleasant)
(2 as AnyObject) === (2 as AnyObject) // false (this makes it clear that there are new objects being generated)
Isso parece um pouco mais consistente com Type 'Int' does not conform to protocol 'AnyObject', no entanto, obtemos
type(of:(1 as AnyObject)) // _SwiftTypePreservingNSNumber.Type
mas a conversão explícita deixa claro que pode haver algo acontecendo. No lado das strings, as coisas NSStringainda estarão disponíveis enquanto nós import Cocoa. Então teremos
var st = "123" // "123"
var ns = (st as NSString) // "123"
st == ns // Compile error with Fixit: 'NSString' is not implicitly convertible to 'String'; did you mean to use 'as' to explicitly convert?
st == ns as String // true, content equality
st === ns // compile error: binary operator '===' cannot be applied to operands of type 'String' and 'NSString'
ns === (st as NSString) // false, new struct
ns === (st as AnyObject) // false, new struct
(st as NSString) === (st as NSString) // false, new structs, bridging is not "free" (as in "lunch")
NSString(string:st) === NSString(string:st) // false, new objects
var st1 = NSString(string:st) // "123"
var st2 = st1 // "123"
st1 === st2 // true
var st3 = (st as NSString) // "123"
st1 === st3 // false
(st as AnyObject) === (st as AnyObject) // false
Ainda é confuso ter duas classes String, mas descartar a conversão implícita provavelmente a tornará um pouco mais palpável.
===operador para comparar Ints. Not in Swift 3.
===não faz sentido para estruturas, pois são tipos de valor. Em particular, há três tipos que você deve ter em mente: tipos literais, como 1 ou "foo", que não foram vinculados a uma variável e normalmente afetam apenas a compilação, pois geralmente você não lida com eles durante o tempo de execução; struct tipos como Inte Stringquais são o que você obtém quando atribui um literal a uma variável e classes como AnyObjecte NSString.
Por exemplo, se você criar duas instâncias de uma classe, por exemplo myClass:
var inst1 = myClass()
var inst2 = myClass()
você pode comparar essas instâncias,
if inst1 === inst2
citado:
que você usa para testar se duas referências a objetos se referem à mesma instância de objeto.
Trecho de: Apple Inc. “A linguagem de programação Swift”. iBooks. https://itun.es/sk/jEUH0.l
Em Swift, temos === simbol, o que significa que ambos os objetos estão se referindo à mesma referência e mesmo endereço
class SomeClass {
var a: Int;
init(_ a: Int) {
self.a = a
}
}
var someClass1 = SomeClass(4)
var someClass2 = SomeClass(4)
someClass1 === someClass2 // false
someClass2 = someClass1
someClass1 === someClass2 // true
Apenas uma pequena contribuição relacionada ao Anyobjeto.
Eu estava trabalhando com testes de unidade NotificationCenter, que faz uso deAny como parâmetro que eu queria comparar para igualdade.
No entanto, como Anynão pode ser usado em uma operação de igualdade, foi necessário alterá-lo. Por fim, decidi pela seguinte abordagem, que me permitiu obter igualdade em minha situação específica, mostrada aqui com um exemplo simplista:
func compareTwoAny(a: Any, b: Any) -> Bool {
return ObjectIdentifier(a as AnyObject) == ObjectIdentifier(b as AnyObject)
}
Esta função tira proveito do ObjectIdentifier , que fornece um endereço exclusivo para o objeto, permitindo que eu teste.
Um item a ser observado ObjectIdentifierpor Apple no link acima:
No Swift, apenas instâncias de classe e metatipos têm identidades exclusivas. Não há noção de identidade para estruturas, enumerações, funções ou tuplas.
==é usado para verificar se duas variáveis são iguais, ie
2 == 2. Porém, no caso de ===representar igualdade, isto é, se duas instâncias referentes ao mesmo objeto exemplo, no caso de classes, for criada uma referência que é mantida por muitas outras instâncias.
Swift 4: Outro exemplo usando testes de unidade que funciona apenas com ===
Nota: O teste abaixo falha com ==, funciona com ===
func test_inputTextFields_Delegate_is_ViewControllerUnderTest() {
//instantiate viewControllerUnderTest from Main storyboard
let storyboard = UIStoryboard(name: "Main", bundle: nil)
viewControllerUnderTest = storyboard.instantiateViewController(withIdentifier: "StoryBoardIdentifier") as! ViewControllerUnderTest
let _ = viewControllerUnderTest.view
XCTAssertTrue(viewControllerUnderTest.inputTextField.delegate === viewControllerUnderTest)
}
E a classe sendo
class ViewControllerUnderTest: UIViewController, UITextFieldDelegate {
@IBOutlet weak var inputTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
inputTextField.delegate = self
}
}
O erro nos testes de unidade se você usar == é, Binary operator '==' cannot be applied to operands of type 'UITextFieldDelegate?' and 'ViewControllerUnderTest!'
==éisEqual:ou equivalência semântica definida por classe.===em Swift está==em (Obj) C - igualdade de ponteiro ou identidade de objeto.