Golang básico - Comparação de Igualdade

Bruno Gomes - Oct 25 - - Dev Community

Esse post faz parte de uma série onde pretendo compartilhar o básico essencial para desenvolver com GoLang.

As comparações lógicas utilizando os operadores == ou != não tem muito mistério. Ou seu código compara se os valores são iguais ou diferentes.
Mas existem alguns detalhes importantes de saber sobre o que você está comparando.

Interface Comparable

A primeira coisa é saber o que pode ser comparado com esses operadores, o lugar mais óbvio para saber disso é a documentação do Go: seção sobre comparadores

E outra opção é olhar a interface comparable, que foi adicionada junto com a implementação de generics do Go, todos os tipos que implementam essa interface são comparáveis.

Então basicamente todos os tipos primitivos definidos pelo Go são comparáveis, como: string, números (int, float, complex), bool.

Comparação de tipos complexos

Alguns tipos possuem condições para serem ou não comparáveis. Que é o caso de: struct, slices e channels.
Somente são comparáveis se os elementos deles também o forem.
O interessante é que o Go valida isso a nível de compilação, te ajudando a evitar erros em runtime, por exemplo:

//Esse código compila e a comparação funciona:
func main() {
    test1 := struct {
        name       string
    }{}
    test2 := struct {
        name       string
    }{}
    if test1 == test2 {
        fmt.Println("Funciona")
    }
}
Enter fullscreen mode Exit fullscreen mode

No código acima estou criando dois structs com o atributos equivalentes e a comparação funciona.

//Esse código não compila
func main() {
    test1 := struct {
        name       string
        attributes map[string]string
    }{}
    test2 := struct {
        name       string
        attributes map[string]string
    }{}
    if test1 == test2 {
        fmt.Println("Cade?")
    }
}
Enter fullscreen mode Exit fullscreen mode

Já esse código vai falhar na compilação com o erro invalid operation.

Isso acontece porque map não é um tipo comparável em Go.

Detalhes sobre structs e map

É bastante conveniente poder comparar structs com ==, já que esse são os tipos onde customizamos nossas modelagens.
Mas mesmo quando estiver utilizando um tipo não comparável há algumas maneiras de simplificar o código, e saber disso vai te poupar de escrever condições bem chatas.

Bom vamos imaginar que estamos trabalhando no sistema de uma escola e temos a seguinte struct não comparável:

type student struct {
    ID         int
    name       string
    age        int
    course     string
    attributes map[string]string
}
Enter fullscreen mode Exit fullscreen mode

A parte boa, esse struct possui um campo ID, o que facilita muito se você estiver trabalhando com dados persistidos.

Agora imagina só se estiver trabalhando com dados ainda transientes, por exemplo se estiver lendo um arquivo e precisar fazer algum tipo de processamento antes de persistir esses dados.

Você sempre vai ter a opção de comparar campo a campo, não é nada conveniente, mas funciona. Mas você pode fazer uso de composição de struct da seguinte forma:

func main() {
    type identity struct {
        name   string
        age    int
        course string
    }
    type student struct {
        ID int
        identity
        attributes map[string]string
    }

    s1 := student{
        identity: identity{
            name:   "Chuck",
            age:    10,
            course: "golang",
        },
        attributes: map[string]string{
            "last_score": "10",
        },
    }
    s2 := student{
        identity: identity{
            name:   "Chuck",
            age:    10,
            course: "golang",
        },
        attributes: map[string]string{
            "last_score": "20",
        },
    }

    s3 := student{
        identity: identity{
            name:   "Chuck",
            age:    12,
            course: "golang",
        },
        attributes: map[string]string{
            "last_score": "20",
        },
    }

    if s1.identity == s2.identity {
        fmt.Println("Achou", s1)
    }

    if s1.identity != s3.identity {
        fmt.Println("Não achou")
    }
}

Enter fullscreen mode Exit fullscreen mode

A alternativa a esse código seria fazer condições como essas:

    if s1.name == s2.name && s1.age == s2.age && s1.course == s2.course {
        fmt.Println("Achou", s1)
    }
Enter fullscreen mode Exit fullscreen mode

Você poderia extrair para uma função, para ficar menos confuso, mas mesmo assim teria que ficar mantendo essas comparações.

Faça bom uso de composição isso pode simplificar bastante o seu código!

Resumo

  • Conheça a interface comparable
  • Tipos primitivos são comparáveis
  • Tipos complexos podem ou não ser comparáveis
  • Use a composição a seu favor.
. . . . . . . .