== e === em Swift: qual a diferença e o que está por baixo dos panos

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Por que existem dois sinais de igualdade em Swift e o que eles escondem?

\n\n

Você já escreveu em Swift e de repente se deparou com o estranho operador ===? O primeiro pensamento: "Erro de digitação? Ou é algum tipo de super-igual?" Na verdade, não é um erro de digitação, mas um mecanismo poderoso que muda radicalmente a lógica de comparação. Se você trabalha com classes, estruturas ou closures, entender a diferença entre == e === não é teoria, é uma necessidade. Sem isso, você corre o risco de ter bugs difíceis de detectar.

\n\n

Neste artigo, vamos olhar "por baixo dos panos" do Swift, analisar como ambos os operadores funcionam e aprender a escolher a ferramenta certa para cada tarefa. Pronto? Vamos lá.

\n\n

O que é o operador de igualdade ==?

\n\n

O operador == é o seu "amigo" padrão para comparar valores. Ele verifica se dois objetos são iguais em termos de conteúdo. Mas há um detalhe: o Swift não sabe o que significa "iguais" para o seu próprio tipo de dado. Portanto, para usar ==, seu tipo deve estar em conformidade com o protocolo Equatable.

\n\n

Veja como funciona para tipos embutidos:

\n\n
let a = 5\nlet b = 5\nprint(a == b) // true, porque os valores são iguais\n\nlet name1 = "Alice"\nlet name2 = "Alice"\nprint(name1 == name2) // true, as strings são iguais
\n\n

Para classes e estruturas, você precisa implementar Equatable manualmente. Por exemplo:

\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, o conteúdo é igual
\n\n

Observe: == compara valores, não referências. Para estruturas isso é óbvio, mas com classes começa a parte interessante.

\n\n

Operador de identidade ===: quando dois objetos são a mesma coisa

\n\n

O operador === (três sinais de igual) verifica não o conteúdo, mas a identidade das referências. Ele responde à pergunta: "As duas variáveis apontam para o mesmo objeto na memória?"

\n\n

Este operador funciona apenas com tipos por referência: classes e closures (closures também são tipos por referência). Para estruturas e enumerações, ele simplesmente não existe — o compilador emitirá um erro.

\n\n

Veja o exemplo:

\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, se Equatable não foi implementado\nprint(car1 === car2) // false, objetos diferentes\nprint(car1 === car3) // true, mesma referência
\n\n

Aqui, car1 e car2 são dois objetos diferentes com o mesmo conteúdo. Já car3 é apenas outro nome para o mesmo objeto que car1. === mostra isso claramente.

\n\n

Como funciona por baixo dos panos: memória e ponteiros

\n\n

Para entender a diferença, precisamos olhar para a memória. Quando você cria uma instância de uma classe, o Swift aloca um espaço para ela no heap e retorna um ponteiro para esse espaço. A variável armazena exatamente o ponteiro, não o objeto em si.

\n\n
    \n
  • == compara o conteúdo através do ponteiro: ele chama sua implementação de Equatable, que pode examinar os campos do objeto.
  • \n
  • === compara os próprios ponteiros: se dois ponteiros apontam para o mesmo endereço de memória, o resultado é true.
  • \n
\n\n

Para estruturas, é mais simples: elas são armazenadas na stack e copiadas quando atribuídas. Portanto, === não faz sentido para elas — duas estruturas diferentes serão sempre objetos diferentes na memória, mesmo que seu conteúdo seja

Blogs

Book Recommendations