En swift parece haber dos operadores de igualdad: el doble igual ( ==
) y el triple igual ( ===
), ¿cuál es la diferencia entre los dos?
En breve:
==
el operador comprueba si sus valores de instancia son iguales, "equal to"
===
el operador comprueba si las referencias apuntan a la misma instancia, "identical to"
Respuesta larga:
Las clases son tipos de referencia, es posible que múltiples constantes y variables se refieran a la misma instancia única de una clase detrás de escena. Las referencias de clase permanecen en la pila de tiempo de ejecución (RTS) y sus instancias permanecen en el área de memoria del montón. Cuando controlas la igualdad ==
significa que sus instancias son iguales entre sí. No necesita ser la misma instancia para ser igual. Para esto, debe proporcionar un criterio de igualdad a su clase personalizada. Por defecto, las clases y estructuras personalizadas no reciben una implementación predeterminada de los operadores de equivalencia, conocidos como el operador "igual a" ==
y el operador "no igual a" !=
. Para hacer esto, su clase personalizada debe cumplir con el Equatable
protocolo y su static func == (lhs:, rhs:) -> Bool
función
Veamos un ejemplo:
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.:
Dado que ssn (número de seguro social) es un número único, no necesita comparar si su nombre es igual o no.
let person1 = Person(ssn: 5, name: "Bob")
let person2 = Person(ssn: 5, name: "Bob")
if person1 == person2 {
print("the two instances are equal!")
}
Aunque las referencias de persona1 y persona2 señalan dos instancias diferentes en el área de Montón, sus instancias son iguales porque sus números ssn son iguales. Entonces la salida seráthe two instance are equal!
if person1 === person2 {
//It does not enter here
} else {
print("the two instances are not identical!")
}
===
operador comprueba si las referencias señalan la misma instancia, "identical to"
. Como person1 y person2 tienen dos instancias diferentes en el área Heap, no son idénticas y la salidathe two instance are not identical!
let person3 = person1
P.S:
Las clases son tipos de referencia y la referencia de person1 se copia a person3 con esta operación de asignación, por lo tanto, ambas referencias apuntan a la misma instancia en el área de Heap.
if person3 === person1 {
print("the two instances are identical!")
}
Son idénticos y la salida será the two instances are identical!
!==
y ===
son operadores de identidad y se utilizan para determinar si dos objetos tienen la misma referencia.
Swift también proporciona dos operadores de identidad (=== y! ==), que puede usar para probar si dos referencias de objeto se refieren a la misma instancia de objeto.
Extracto de: Apple Inc. "El lenguaje de programación Swift". iBooks https://itun.es/us/jEUH0.l
==
esisEqual:
, o equivalencia semántica definida por clase.===
en Swift está==
en (Obj) C: igualdad de puntero o identidad de objeto.var
olet
) de un nombre a un valor es una copia única, por lo que no tiene sentido crear punteros porque el valor al que hizo un puntero es un valor diferente al que creó por primera vez. Otra es que la definición de la semántica de valores de Swift abstrae el almacenamiento: el compilador es libre de optimizar, hasta e incluso nunca almacenar su valor en una ubicación de memoria accesible más allá de la línea donde se usa (registro, codificación de instrucciones, etc.).Tanto en Objective-C y Swift, el
==
y!=
prueba de los operadores para la igualdad de valor para valores de número (por ejemplo,NSInteger
,NSUInteger
,int
, en Objective-C yInt
,UInt
, etc. en Swift). Para objetos (NSObject / NSNumber y subclases en Objective-C y tipos de referencia en Swift),==
y!=
compruebe que los objetos / tipos de referencia son la misma cosa idéntica, es decir, el mismo valor hash, o no son la misma cosa idéntica, respectivamente .Los operadores de igualdad de identidad de Swift ,
===
y!==
comprueban la igualdad referencial, y por lo tanto, probablemente deberían llamarse los operadores de igualdad referencial IMO.También vale la pena señalar que los tipos de referencia personalizados en Swift (que no subclasifican una clase que se ajusta a Equatable) no implementan automáticamente los operadores igual a igual, pero los operadores de igualdad de identidad aún se aplican. Además, al implementar
==
,!=
se implementa automáticamente.Estos operadores de igualdad no se implementan para otros tipos, como estructuras en cualquier idioma. Sin embargo, se pueden crear operadores personalizados en Swift, lo que, por ejemplo, le permitiría crear un operador para verificar la igualdad de un CGPoint.
fuente
==
no prueba laNSNumber
igualdad en Objective-C.NSNumber
es unaNSObject
prueba de identidad. La razón por la que A VECES funciona es debido a punteros etiquetados / literales de objetos en caché. Fallará para números suficientemente grandes y en dispositivos de 32 bits al comparar no literales.En Swift 3 y superior
===
(o!==
)==
en Obj-C (igualdad de puntero).==
(o!=
)isEqual:
comportamiento predeterminado en Obj-C.Aquí comparo tres instancias (la clase es un tipo de referencia)
fuente
isEqual:
en Swift:override func isEqual(_ object: Any?) -> Bool {}
Hay sutilezas con Swifts
===
que van más allá de la simple aritmética de punteros. Mientras que en Objective-C pudiste comparar dos punteros (es decir,NSObject *
) con==
esto ya no es cierto en Swift ya que los tipos juegan un papel mucho más importante durante la compilación.Un patio de juegos te dará
Con cadenas tendremos que acostumbrarnos a esto:
pero también puedes divertirte de la siguiente manera:
Estoy seguro de que puedes pensar en muchos más casos divertidos :-)
Actualización para Swift 3 (como sugiere el comentario de Jakub Truhlář)
Esto parece un poco más consistente con
Type 'Int' does not conform to protocol 'AnyObject'
, sin embargo, entonces obtenemospero la conversión explícita deja en claro que podría estar sucediendo algo. En el lado de las cadenas, las cosas
NSString
seguirán estando disponibles mientras nosotrosimport Cocoa
. Entonces tendremosTodavía es confuso tener dos clases de String, pero eliminar la conversión implícita probablemente la haga un poco más palpable.
fuente
===
operador para compararInts
. No en Swift 3.===
no tiene sentido para las estructuras ya que son tipos de valor. En particular, hay tres tipos que debe tener en cuenta: los tipos literales, como 1 o "foo", que no se han vinculado a una variable y normalmente solo afectan la compilación, ya que generalmente no se trata con ellos durante el tiempo de ejecución; tipos de estructura comoInt
yString
que son lo que obtienes cuando asignas un literal a una variable, y clases comoAnyObject
yNSString
.Por ejemplo, si crea dos instancias de una clase, por ejemplo
myClass
:puedes comparar esas instancias,
citado:
Extracto de: Apple Inc. "El lenguaje de programación Swift". iBooks https://itun.es/sk/jEUH0.l
fuente
En Swift tenemos === simbol, lo que significa que ambos objetos se refieren a la misma referencia, la misma dirección
fuente
Solo una pequeña contribución relacionada con el
Any
objeto.Estaba trabajando con pruebas unitarias
NotificationCenter
, que utilizanAny
como parámetro que quería comparar para la igualdad.Sin embargo, dado
Any
que no se puede utilizar en una operación de igualdad, fue necesario cambiarlo. Finalmente, me decidí por el siguiente enfoque, que me permitió obtener la igualdad en mi situación específica, que se muestra aquí con un ejemplo simplista:Esta función aprovecha ObjectIdentifier , que proporciona una dirección única para el objeto, lo que me permite probar.
Un elemento a tener en cuenta
ObjectIdentifier
por Apple en el enlace anterior:fuente
==
se utiliza para verificar si dos variables son iguales, es decir2 == 2
. Pero en el caso de===
que signifique igualdad, es decir, si dos instancias se refieren al mismo ejemplo de objeto en el caso de clases, se crea una referencia que es mantenida por muchas otras instancias.fuente
Swift 4: otro ejemplo usando pruebas unitarias que solo funciona con ===
Nota: La prueba a continuación falla con ==, funciona con ===
Y la clase siendo
El error en las pruebas unitarias si usa == es,
Binary operator '==' cannot be applied to operands of type 'UITextFieldDelegate?' and 'ViewControllerUnderTest!'
fuente