Trabalhando com interfaces

Go é uma linguagem de tipagem forte, ou seja, se eu declarar uma variável do tipo int ela só aceitará valores inteiros. Pode parecer óbvio, no entanto em algumas linguagens é totalmente possível iniciar uma variável como int e no meio do código atribuir um valor do tipo float ou as vezes até mesmo string.

Uma outra diferença do Go com outras linguagens é que em Go não temos o conceito de Orientação a Objetos. Contudo, quando precisamos lidar com um grupo de valores mais complexos, temos a possibilidade de criar nossas próprias estruturas de dados, as structs.

Com isso em mente, sempre que declaramos uma função em Go, precisamos setar o tipo de dado esperado em cada um dos parâmetros, onde muitas vezes esses parâmetros esperam uma struct.

Não existe nenhum problema em usar struct como parâmetro, porém isso pode limitar um pouco a reutilização da função. Caso seja interessante reutilizar a função para vários tipos de struct diferentes, criar uma interface irá fornecer essa possiblidade.

Em Go, as interfaces fornecem um conjunto de métodos (com suas assinaturas) que se espera que a struct tenha implementado.

Para exemplificar o que foi dito até aqui, vamos imaginar que estamos implementando um programa infantil, que quando a criança clica em um animal, o programa retorna o som que esse animal faz.

Isso poderia ser feito com um switch/case gigantesco, mas para nossa sanidade mental e facilidade de expandir as funcionalidades desse programa, vamos desenha-lo usando o conceito de interface.

Vamos iniciar ele criando nossa interface.

type Animal interface {
    Onomatopeia() string
}

Com essa interface em mãos, podemos criar 2 structs totalmente independentes.

type Urso struct {}
func (u Urso) Onomatopeia() string {
    return "Roarrrrr"
}

type Tucano struct {}
func (t Tucano) Onomatopeia() string {
    return "Tri tri tri"
}

Agora ao invés de ter um monte de ifs ou como eu disse acima, um switch/case gigantesco, tudo que precisamos fazer é implementar uma função que receba a interface Animal.

func Play(animal Animal) {
    fmt.Println(animal.Onomatopeia())
}

Embora o exemplo seja simples, ele dá uma boa visão de como conseguimos simplificar nossos programas quando utilizamos interfaces.

ATENÇÃO!!!!

Sim, as vezes é necessário… no entanto EVITE AO MÁXIMO criar funções do tipo:

func Play(animal interface{}) {
    fmt.Println(animal.Onomatopeia())
}

Declarar um parâmetro como interface{}, ou seja, como uma interface vazia, não garante que a struct que será passada tem o método Onomatopeia() implementado.

É como Rob Pike disse em uma de suas apresentações:

Uma interface vazia não diz nada!

Rob Pike

Deixem suas dúvidas nos comentários.

Até a próxima!


Subscreva

Fique por dentro de tudo o que acontece no mundo Go

Deixe uma resposta