== y === en Swift: cuál es la diferencia y qué hay bajo el capó

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

¿Por qué hay dos signos de igualdad en Swift y qué esconden?

\n\n

¿Alguna vez has escrito código en Swift y te has topado con el extraño operador ===? El primer pensamiento: "¿Un error tipográfico? ¿O es una especie de super-igual?" En realidad, no es un error tipográfico, sino un mecanismo poderoso que cambia radicalmente la lógica de comparación. Si trabajas con clases, estructuras o closures, entender la diferencia entre == y === no es teoría, sino una necesidad. Sin esto, corres el riesgo de tener errores difíciles de detectar.

\n\n

En este artículo, miraremos "bajo el capó" de Swift, analizaremos cómo funcionan ambos operadores y aprenderemos a elegir la herramienta correcta para cada tarea. ¿Listos? ¡Allá vamos.

\n\n

¿Qué es el operador de igualdad ==?

\n\n

El operador == es tu "amigo" estándar para comparar valores. Verifica si dos objetos son iguales por su contenido. Pero hay un detalle: Swift no sabe qué significa "iguales" para tu propio tipo de dato. Por lo tanto, para usar ==, tu tipo debe cumplir con el protocolo Equatable.

\n\n

Así es como se ve para los tipos incorporados:

\n\n
let a = 5\nlet b = 5\nprint(a == b) // true, porque los valores son iguales\n\nlet name1 = "Alice"\nlet name2 = "Alice"\nprint(name1 == name2) // true, las cadenas son iguales
\n\n

Para clases y estructuras, debes implementar Equatable tú mismo. Por ejemplo:

\n\n
struct User {\n    let id: Int\n    let name: String\n}\n\nextension User: Equatable {\n    static func == (lhs: User, rhs: User) -> Bool {\n        return lhs.id == rhs.id && lhs.name == rhs.name\n    }\n}\n\nlet user1 = User(id: 1, name: "John")\nlet user2 = User(id: 1, name: "John")\nprint(user1 == user2) // true, el contenido coincide
\n\n

Observa: == compara valores, no referencias. Para las estructuras esto es obvio, pero con las clases comienza lo interesante.

\n\n

Operador de identidad ===: cuando dos objetos son lo mismo

\n\n

El operador === (triple igual) no verifica el contenido, sino la identidad de las referencias. Responde a la pregunta: "¿Apuntan dos variables al mismo objeto en memoria?"

\n\n

Este operador funciona solo con tipos por referencia: clases y closures (los closures también son tipos por referencia). Para estructuras y enumeraciones simplemente no existe: el compilador dará un error.

\n\n

Mira el ejemplo:

\n\n
class Car {\n    var model: String\n    init(model: String) {\n        self.model = model\n    }\n}\n\nlet car1 = Car(model: "Tesla")\nlet car2 = Car(model: "Tesla")\nlet car3 = car1\n\nprint(car1 == car2) // false, si no se implementó Equatable\nprint(car1 === car2) // false, objetos diferentes\nprint(car1 === car3) // true, la misma referencia
\n\n

Aquí car1 y car2 son dos objetos diferentes con el mismo contenido. Y car3 es simplemente otro nombre para el mismo objeto que car1. === lo muestra claramente.

\n\n

Cómo funciona bajo el capó: memoria y punteros

\n\n

Para entender la diferencia, hay que mirar la memoria. Cuando creas una instancia de una clase, Swift reserva un espacio en el montón (heap) y devuelve un puntero a ese espacio. La variable almacena el puntero, no el objeto en sí.

\n\n
    \n
  • == compara el contenido a través del puntero: llama a tu implementación de Equatable, que puede revisar los campos del objeto.
  • \n
  • === compara los punteros en sí: si dos punteros apuntan a la misma dirección en memoria, el resultado es true.
  • \n
\n\n

Para las estructuras es más simple: se almacenan en la pila (stack) y se copian al asignarse. Por lo tanto, === no tiene sentido para ellas: dos estructuras diferentes siempre serán objetos distintos en memoria, incluso si su contenido es

Blogs

Book Recommendations