Conteúdo

Interfaces

Interfaces em Go são coleções de métodos agrupadas por um nome em comum. Sua declaração é parecida com a de structs; no entanto seu corpo define assinaturas de métodos, não campos.

Sintaxe:

type Formatador interface {
    Formata(string) string // Assinatura do(s) método(s)
}

Para compreendermos melhor a utilidade real dessa característica da linguagem, consideremos o caso de um cachorro. Apesar de diferentes raças de cachorro latirem de modo diferente, todas elas latem. Isso seria exemplificado do seguinte modo, definindo um método que não recebe nem retorna nada:

type Cachorro interface {
    Latir()
}

Em muitas linguagens de programação orientadas a objetos, structs ou classes implementam interfaces de modo explícito, utilizando a keyword implements e então o nome da interface. Este não é o caso de Go: interpretamos que uma struct implementa uma interface de modo implícito, ou seja, se ela implementar todos os métodos requeridos por uma interface, ela satisfaz essa interface.

Por exemplo, as seguintes structs implementam e satisfazem a interface Cachorro:

type Pinscher struct{}

func (p Pinscher) Latir() {
      fmt.Println(au au au)
}

type Rottweiler struct {}

func (r Rottweiler) Latir() {
	fmt.Println(WOOF WOOF)
}

Se agora tivermos uma função ProtegerCasa() que receba uma interface do tipo Cachorro, poderíamos usar as instâncias de ambas as raças de cachorros intercambiavelmente:

Uma interface pode conter métodos, outras interfaces (via composição, desse modo englobando todos os métodos definidos pela interface composta) ou nada.

Este último caso, no entanto, conhecido como interface vazia (empty interface ou interface{}) , vale a atenção, pois todos os tipos a satisfazem (todos os tipos implementam ao menos nenhum método). A interface vazia é utilizada como um “tipo coringa” em momentos em que não sabemos o tipo em que iremos operar (um dos mais famosos exemplos sendo a função fmt.Printf(), que aceita qualquer tipo de parâmetro).

Para descobrir o tipo de uma interface vazia utilizamos a sintaxe de type assertion, por exemplo:

Na linha 2, se i for do tipo int, t1 será um int; caso contrário, um panic ocorre.

Na linha 3, se i for do tipo float, t2 será um float; caso contrário, um erro é retornado (isto é conhecido como idioma “comma ok”. É opcional e preferível, pois evita panics.

Uma interface muito utilizada é a Reader, do pacote io. Ela define o seguinte método, que lê bytes de um array de bytes e retorna o número de bytes lidos e um erro, caso aconteça.

Muitos tipos implementam a interface Reader. Caso estejamos trabalhando com algum tipo que não a implemente, podemos criar funções que atuam como construtores de Readers. Por exemplo, para criarmos um reader de um slice de bytes utilizamos o bytes.NewReader([]byte) e de uma string o strings.NewReader(string).

Last updated