Interfaces Avançadas em Go 2026: Composição, Asserções de Tipo e Perguntas de Entrevista
Dominar a composição de interfaces Go, asserções de tipo e genéricos autorreferenciais do Go 1.26. Inclui exemplos práticos e perguntas de entrevista técnica.

As interfaces em Go definem comportamento sem prescrever implementação, tornando-as centrais para escrever código flexível e testável. Go 1.26 estende esse poder com genéricos autorreferenciais, novos iteradores de reflexão e tratamento de erros type-safe via errors.AsType. Este guia cobre composição de interfaces, asserções de tipo, padrões de embedding e as perguntas que surgem em entrevistas técnicas.
Tipos genéricos agora podem se referenciar em sua lista de parâmetros de tipo: type Adder[A Adder[A]] interface { Add(A) A }. Este padrão de polimorfismo F-bounded permite interfaces que restringem tipos de retorno ao próprio tipo implementador.
Composição de Interfaces e Padrões de Embedding
O embedding de interfaces combina múltiplas interfaces em um único contrato. O resultado é uma nova interface que requer todos os métodos de suas interfaces incorporadas. Este padrão evita duplicação e cria limites de abstração claros.
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
type Closer interface {
Close() error
}
// Composed interface embedding three interfaces
type ReadWriteCloser interface {
Reader
Writer
Closer
}Qualquer tipo que implemente os métodos Read, Write e Close automaticamente satisfaz ReadWriteCloser. A biblioteca padrão do Go usa este padrão extensivamente no pacote io.
Uma pergunta comum de entrevista pede aos candidatos que expliquem por que Go prefere interfaces pequenas e focadas. A resposta está na composabilidade: io.Reader aparece em centenas de funções porque exige exatamente um método. Interfaces maiores criam acoplamento mais forte e reduzem a reutilização.
Asserções de Tipo: Sintaxe e Segurança
Asserções de tipo extraem um tipo concreto de um valor de interface. A forma de dois valores previne panics retornando um booleano indicando sucesso.
func processValue(v interface{}) {
// Two-value assertion: safe, no panic
if str, ok := v.(string); ok {
fmt.Printf("String value: %s\n", str)
return
}
// Type switch for multiple types
switch val := v.(type) {
case int:
fmt.Printf("Integer: %d\n", val)
case float64:
fmt.Printf("Float: %.2f\n", val)
case []byte:
fmt.Printf("Bytes: %x\n", val)
default:
fmt.Printf("Unknown type: %T\n", val)
}
}Type switches lidam com múltiplos tipos possíveis de forma limpa. Cada caso vincula val ao tipo afirmado dentro de seu bloco, eliminando a necessidade de asserções separadas.
Asserções de valor único como str := v.(string) causam panic se a asserção falhar. Código em produção deve sempre usar a forma de dois valores ou um type switch.
Os entrevistadores frequentemente perguntam sobre o desempenho das asserções de tipo. O runtime realiza uma única comparação de descritores de tipo, tornando as asserções baratas. O custo aumenta com valores de interface que envolvem ponteiros para structs grandes devido à indireção, mas a asserção em si permanece O(1).
Genéricos Autorreferenciais no Go 1.26
Go 1.26 introduziu parâmetros de tipo autorreferenciais, permitindo interfaces onde métodos devem retornar o tipo implementador. Este padrão, às vezes chamado de polimorfismo F-bounded, resolve uma limitação de longa data.
// Self-referential interface: methods return the same type
type Builder[B Builder[B]] interface {
WithName(name string) B
WithAge(age int) B
Build() string
}
type PersonBuilder struct {
name string
age int
}
func (p PersonBuilder) WithName(name string) PersonBuilder {
p.name = name
return p
}
func (p PersonBuilder) WithAge(age int) PersonBuilder {
p.age = age
return p
}
func (p PersonBuilder) Build() string {
return fmt.Sprintf("%s, %d years old", p.name, p.age)
}
// Generic function using the self-referential constraint
func configure[B Builder[B]](b B, name string, age int) string {
return b.WithName(name).WithAge(age).Build()
}A restrição Builder[B] garante que WithName e WithAge retornem B, não um Builder genérico. Sem isso, o tipo de retorno seria a interface, perdendo a informação do tipo concreto e quebrando o encadeamento de métodos.
Tipos matemáticos se beneficiam deste padrão. Uma interface Addable[A Addable[A]] garante que Add(A) A retorne o mesmo tipo numérico, prevenindo a mistura acidental de valores BigInt e Decimal.
errors.AsType: Unwrapping de Erros Type-Safe
Go 1.26 adicionou errors.AsType, substituindo o padrão de dança de ponteiros de errors.As. A versão genérica retorna o erro unwrapped diretamente.
type ValidationError struct {
Field string
Message string
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("validation failed on %s: %s", e.Field, e.Message)
}
func handleError(err error) {
// Go 1.26: generic type-safe unwrapping
if valErr, ok := errors.AsType[*ValidationError](err); ok {
log.Printf("Validation error on field %s\n", valErr.Field)
return
}
// Before Go 1.26: pointer-based unwrapping
// var valErr *ValidationError
// if errors.As(err, &valErr) { ... }
log.Printf("Unexpected error: %v\n", err)
}A nova API elimina a declaração de variável separada e torna o tipo alvo explícito na chamada de função. As cadeias de erros são pesquisadas da mesma forma que antes; apenas a interface mudou.
Pronto para mandar bem nas entrevistas de Go?
Pratique com nossos simuladores interativos, flashcards e testes tecnicos.
Iteradores de Reflexão para Inspeção de Interfaces
Go 1.26 adicionou métodos iteradores ao pacote reflect. Type.Methods() e Value.Methods() retornam iteradores para percorrer métodos, substituindo loops baseados em índice.
import "reflect"
func inspectInterface(v interface{}) {
t := reflect.TypeOf(v)
// Go 1.26: iterator-based method inspection
fmt.Printf("Type %s methods:\n", t.Name())
for method := range t.Methods() {
fmt.Printf(" %s: %s\n", method.Name, method.Type)
}
// For struct fields (also new in 1.26)
if t.Kind() == reflect.Struct {
for field := range t.Fields() {
fmt.Printf(" Field: %s (%s)\n", field.Name, field.Type)
}
}
}O padrão de iterador se alinha com o recurso range-over-function do Go 1.23. O código se torna mais legível, e não há penalidade de desempenho: iteradores produzem valores de forma lazy.
Satisfação de Interface em Tempo de Compilação
Go verifica a satisfação de interface em tempo de compilação ao atribuir um valor concreto a uma variável de interface. Verificações explícitas usando atribuições com identificador em branco detectam erros cedo em bases de código grandes.
type Storage interface {
Save(key string, data []byte) error
Load(key string) ([]byte, error)
Delete(key string) error
}
type FileStorage struct {
basePath string
}
// Compile-time check: fails if FileStorage misses a method
var _ Storage = (*FileStorage)(nil)
func (f *FileStorage) Save(key string, data []byte) error {
path := filepath.Join(f.basePath, key)
return os.WriteFile(path, data, 0644)
}
func (f *FileStorage) Load(key string) ([]byte, error) {
path := filepath.Join(f.basePath, key)
return os.ReadFile(path)
}
func (f *FileStorage) Delete(key string) error {
return os.Remove(filepath.Join(f.basePath, key))
}A linha var _ Storage = (*FileStorage)(nil) compila apenas se *FileStorage satisfizer Storage. Este padrão detecta métodos faltantes imediatamente em vez de em runtime quando um valor é atribuído.
A Interface Vazia e Restrições de Tipo
A interface vazia interface{} aceita qualquer valor, enquanto any é seu alias desde Go 1.18. Restrições genéricas fornecem segurança de tipo em tempo de compilação sem asserções em runtime.
import "golang.org/x/exp/constraints"
// Generic function with numeric constraint
func Sum[T constraints.Integer | constraints.Float](values []T) T {
var total T
for _, v := range values {
total += v
}
return total
}
// Comparable constraint for map keys
func Contains[K comparable, V any](m map[K]V, key K) bool {
_, exists := m[key]
return exists
}Preferir genéricos sobre interface{} elimina asserções de tipo e detecta incompatibilidades de tipo em tempo de compilação. A compensação é complexidade adicional nas assinaturas de função, então genéricos se encaixam melhor quando uma função genuinamente opera sobre múltiplos tipos.
Perguntas de Entrevista Técnica sobre Interfaces Go
Os entrevistadores testam conhecimento de interfaces em múltiplos níveis. Aqui estão perguntas comuns com respostas concisas.
P: O que acontece quando se chama um método em um valor de interface nil versus um valor concreto nil dentro de uma interface?
Uma interface nil não tem tipo nem valor; chamar qualquer método causa panic. Uma interface não-nil contendo um ponteiro nil tem um tipo; o método executa com um receiver nil. Este comportamento permite padrões como (*bytes.Buffer)(nil).String() retornando uma string vazia.
P: Como funciona a comparação de interfaces?
Dois valores de interface são iguais se tiverem o mesmo tipo dinâmico e valores dinâmicos iguais. Comparar interfaces com tipos não comparáveis (slices, maps, funções) causa panic em runtime.
P: Quando um método deve usar um receiver de ponteiro versus um receiver de valor?
Receivers de ponteiro permitem mutação e evitam copiar structs grandes. Receivers de valor são seguros para uso concorrente e funcionam tanto com valores quanto com ponteiros. Se algum método precisa de um receiver de ponteiro, todos os métodos nesse tipo devem usar receivers de ponteiro por consistência, já que apenas *T satisfaz uma interface que requer um método com receiver de ponteiro.
type Counter struct {
count int
}
// Pointer receiver: modifies the struct
func (c *Counter) Increment() {
c.count++
}
// Value receiver: read-only operation
func (c Counter) Value() int {
return c.count
}
type Incrementer interface {
Increment()
}
func main() {
var c Counter
// var i Incrementer = c // Compile error: Counter lacks Increment
var i Incrementer = &c // OK: *Counter has Increment
i.Increment()
}P: Explicar o princípio "aceitar interfaces, retornar structs".
Funções que aceitam interfaces se desacoplam de implementações concretas, permitindo testes com mocks. Retornar tipos concretos dá aos chamadores acesso completo aos métodos do tipo sem asserções de tipo. Retornar uma interface esconde futuras adições de métodos atrás de uma asserção de tipo.
Para mais preparação para entrevistas Go, veja o módulo de perguntas sobre concorrência Go e o módulo de testing.
Quando pedido para projetar uma interface, começar com o caso de método único. Expandir apenas quando múltiplos métodos são sempre chamados juntos. As interfaces Stringer, Reader e Handler da biblioteca padrão definem cada uma um único método.
O que Desenvolvedores Go Sênior Devem Saber sobre Interfaces
- A composição de interfaces através de embedding cria contratos flexíveis sem hierarquias de herança. Manter interfaces pequenas: um a três métodos cobre a maioria dos casos de uso.
- Asserções de tipo e type switches extraem tipos concretos com segurança. Sempre usar a forma de dois valores ou um switch em código de produção para evitar panics.
- Os genéricos autorreferenciais do Go 1.26 permitem padrões builder e tipos matemáticos onde métodos devem retornar o tipo implementador.
errors.AsTypesimplifica o unwrapping de erros com uma API genérica e type-safe. Usar em código novo direcionado ao Go 1.26 ou posterior.- Verificações de interface em tempo de compilação com
var _ Interface = (*Type)(nil)detectam métodos faltantes antes dos testes executarem. - Preferir genéricos sobre
interface{}quando a segurança de tipo em tempo de compilação supera a complexidade nas assinaturas. - A diretriz "aceitar interfaces, retornar structs" mantém APIs flexíveis para chamadores enquanto expõe funcionalidade completa.
Comece a praticar!
Teste seus conhecimentos com nossos simuladores de entrevista e testes tecnicos.
Você saberia encontrar o bug em Go?
Um trecho real, um bug escondido, uma tentativa por dia. Sem conta para testar.

Escrito por
Anthony Fillion-MailletFundador da SharpSkill
Desenvolvedor fullstack há mais de 10 anos. Dirige a SharpSkill e responde por tudo o que é publicado aqui.
Atualizado em 10 de setembro de 2026
Tags
Compartilhar
Artigos relacionados

Perguntas de Entrevista sobre Go 1.26: Green Tea GC, go fix e Novos Recursos
Guia completo sobre os novos recursos do Go 1.26 para entrevistas técnicas, incluindo Green Tea GC, otimizações de stack para slices, go fix modernizado e melhorias em generics.

O Pacote context do Go em 2026: Cancelamento, Timeouts e Perguntas de Entrevista
Guia completo sobre o pacote context do Go: gerenciamento de cancelamento, timeouts e deadlines. Inclui perguntas frequentes de entrevistas técnicas e melhores práticas de produção.

Go SIMD e o Pacote ArchSIMD em 2026: Otimização de Performance e Perguntas de Entrevista
Descubra o pacote simd/archsimd do Go 1.26: operações vetoriais nativas, otimização de performance e preparação para entrevistas técnicas de Go.