Na sua forma mais simples, um tipo de interface é um conjunto de assinaturas de métodos.
Veja um exemplo de definição de interface que inclui dois métodos, Add e Value:
type Counter interface {
Add(increment int)
Value() int
}
Os nomes dos parâmetros, como increment, podem ser omitidos da definição da interface, mas eles costumam aumentar a legibilidade.
Os nomes de interfaces em Go não contêm a palavra Interface nem I.
Em vez disso, eles costumam terminar com er, por exemplo Reader e Stringer.
Qualquer tipo que defina os métodos da interface automaticamente "implementa" a interface, de forma implícita.
Não existe a palavra-chave implements em Go.
O tipo a seguir implementa a interface Counter que vimos acima.
type Stats struct {
value int
// ...
}
func (s Stats) Add(v int) {
s.value += v
}
func (s Stats) Value() int {
return s.value
}
func (s Stats) SomeOtherMethod() {
// The type can have additional methods not mentioned in the interface.
}
Para implementar a interface, não importa se o método tem receptor de valor ou de ponteiro. (Reveja o conceito de métodos caso tenha dúvidas sobre isso.)
Um valor de tipo interface pode conter qualquer valor que implemente esses métodos. 1
Isso significa que Stats agora pode ser usado em todos os lugares que esperam a interface Counter.
func SetUpAnalytics(counter Counter) {
// ...
}
stats := Stats{}
SetUpAnalytics(stats)
// works because Stats implements Counter
Se todos os parâmetros e valores de retorno de funções precisassem usar tipos concretos (ou seja, que não são interfaces), isso limitaria muito a reutilização delas. Ao usar tipos de interface nos parâmetros, define-se apenas o comportamento necessário para a função fazer o seu trabalho. Assim, a função pode ser usada com parâmetros de tipos concretos diferentes, desde que esses tipos concretos implementem a interface. A mesma lógica vale ao usar tipos de interface como valores de retorno.
Como as interfaces são implementadas de forma implícita, um tipo pode implementar várias interfaces com facilidade. Basta que ele tenha todos os métodos necessários definidos.
Definições de interface podem incluir outras interfaces. Veja um exemplo da biblioteca padrão.
type ReadCloser interface {
Reader
Closer
}
// Based on these interfaces:
type Reader interface {
Read(p []byte) (n int, err error)
}
type Closer interface {
Close() error
}
Em vez de repetir as assinaturas dos métodos Read e Close para definir ReadCloser, a definição da interface usa as definições existentes de Reader e Closer.
Existe um tipo de interface muito especial em Go, o tipo interface vazia, que não contém nenhum método.
A interface vazia é escrita assim: interface{}.
No Go 1.18 ou superior, também é possível usar any.
Ele foi definido como um alias.
Como a interface vazia não tem métodos, todo tipo a implementa de forma implícita. Isso é útil para definir uma função que aceita qualquer valor de forma genérica. Nesse caso, o parâmetro da função usa o tipo interface vazia.
Por exemplo:
func AnythingGoes(i interface{}) string {
if i == 0 {
return "zero"
}
if i == "" {
return "empty string"
}
return "something else"
}