# 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. - Published: 2026-09-10 - Updated: 2026-09-10 - Author: Anthony Fillion-Maillet - Tags: go, interfaces, type-assertions, generics, go-1.26 - Reading time: 12 min --- 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. > **Melhoria de Interfaces no Go 1.26** > > 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. ```go // interfaces.go 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](https://pkg.go.dev/io) 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. ```go // assertions.go 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. > **Risco de Panic** > > 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](https://en.wikipedia.org/wiki/Bounded_quantification#F-bounded_quantification), resolve uma limitação de longa data. ```go // builder.go // 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`](https://pkg.go.dev/errors#AsType), substituindo o padrão de dança de ponteiros de `errors.As`. A versão genérica retorna o erro unwrapped diretamente. ```go // errors_handling.go 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. ## 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. ```go // reflection.go 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. ```go // compile_check.go 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. ```go // constraints.go 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. ```go // receiver_rules.go 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](/technologies/go/interview-questions/concurrency-patterns) e o [módulo de testing](/technologies/go/interview-questions/testing). > **Dica de Entrevista** > > 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.AsType` simplifica 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. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/pt/blog/go/go-interfaces-advanced-composition-type-assertions-2026