<h2>Embedding em Go: O que é e Por Que Importa</h2>
<p>Embedding é um mecanismo poderoso em Go que permite que você reutilize código e comportamento através da composição, não herança. Diferentemente de linguagens como Java ou C++, Go não oferece herança tradicional com classes. Em vez disso, usa composição: você "embutir" um tipo dentro de outro para aproveitar seus campos e métodos.</p>
<p>Quando você embutir uma struct ou interface dentro de outra, o Go automaticamente promove os campos e métodos do tipo embutido para o tipo externo. Isso significa que você pode acessar membros diretos sem precisar especificar o caminho completo. É uma forma elegante de reutilizar funcionalidades mantendo código simples e testável.</p>
<h2>Embedding de Structs: Composição Prática</h2>
<h3>Conceito Fundamental</h3>
<p>O embedding de structs é a forma mais comum e intuitiva de reutilizar código em Go. Quando você inclui um tipo nomeado (outra struct) sem um nome de campo dentro de uma struct, os campos e métodos daquele tipo são promovidos automaticamente. Você acessa-os diretamente como se fossem do tipo externo.</p>
<p>Considere um exemplo prático: você tem uma struct <code>Animal</code> com propriedades comuns e quer criar um <code>Cachorro</code> que herda essas características. Em Go, você não herda, você compõe:</p>
<pre><code class="language-go">package main
import "fmt"
type Animal struct {
Nome string
Idade int
}
func (a Animal) Fazer() string {
return fmt.Sprintf("%s tem %d anos", a.Nome, a.Idade)
}
type Cachorro struct {
Animal // Embedding sem nome de campo
Raca string
}
func main() {
dog := Cachorro{
Animal: Animal{Nome: "Rex", Idade: 5},
Raca: "Labrador",
}
// Acesso direto aos campos promovidos
fmt.Println(dog.Nome) // Rex
fmt.Println(dog.Fazer()) // Rex tem 5 anos
fmt.Println(dog.Raca) // Labrador
}</code></pre>
<p>Observe que <code>Cachorro</code> não precisa definir seu próprio campo <code>Nome</code> — ele herda esse acesso automaticamente. O método <code>Fazer()</code> também é promovido e pode ser chamado diretamente em instâncias de <code>Cachorro</code>. Esta é a beleza do embedding: simplicidade com reutilização.</p>
<h3>Shadowing: Quando Você Sobrescreve Comportamento</h3>
<p>Às vezes, você precisa modificar ou estender o comportamento de um tipo embutido. Em Go, isso é feito redefinindo um método no tipo externo. Quando você faz isso, o método externo "sombra" o método interno, mas você ainda pode acessar o método original através do nome do tipo embutido.</p>
<pre><code class="language-go">package main
import "fmt"
type Veiculo struct {
Marca string
Ano int
}
func (v Veiculo) Descricao() string {
return fmt.Sprintf("Veículo %s (%d)", v.Marca, v.Ano)
}
type Carro struct {
Veiculo
Portas int
}
// Shadowing: redefinindo o método Descricao
func (c Carro) Descricao() string {
return fmt.Sprintf("%s com %d portas", c.Veiculo.Descricao(), c.Portas)
}
func main() {
car := Carro{
Veiculo: Veiculo{Marca: "Toyota", Ano: 2022},
Portas: 4,
}
fmt.Println(car.Descricao()) // Veículo Toyota (2022) com 4 portas
fmt.Println(car.Veiculo.Descricao()) // Veículo Toyota (2022)
}</code></pre>
<p>Aqui, <code>Carro</code> redefine <code>Descricao()</code>, mas ainda pode chamar o método original através de <code>c.Veiculo.Descricao()</code>. Isso oferece flexibilidade: você estende funcionalidade sem perder o acesso à implementação original.</p>
<h2>Embedding de Interfaces: Composição de Comportamentos</h2>
<h3>Combinando Interfaces</h3>
<p>Assim como você pode embutir structs, também pode embutir interfaces dentro de outras interfaces. Isso permite que você crie interfaces maiores e mais especializadas a partir de interfaces menores e focadas. Este é um padrão excelente para manter código modular e testável.</p>
<pre><code class="language-go">package main
import "fmt"
type Leitor interface {
Ler() string
}
type Escritor interface {
Escrever(data string) error
}
// Interface composta (embedding)
type LeitorEscritor interface {
Leitor
Escritor
}
type Arquivo struct {
conteudo string
}
func (a *Arquivo) Ler() string {
return a.conteudo
}
func (a *Arquivo) Escrever(data string) error {
a.conteudo = data
fmt.Printf("Escrito: %s\n", data)
return nil
}
func Processar(rw LeitorEscritor) {
dados := rw.Ler()
rw.Escrever(fmt.Sprintf("Processado: %s", dados))
}
func main() {
arquivo := &Arquivo{conteudo: "dados originais"}
Processar(arquivo)
fmt.Println(arquivo.Ler()) // Processado: dados originais
}</code></pre>
<p>Neste exemplo, <code>LeitorEscritor</code> embutir <code>Leitor</code> e <code>Escritor</code>, criando uma interface que exige ambos os comportamentos. Qualquer tipo que implemente ambas as interfaces satisfaz <code>LeitorEscritor</code>. Isso reduz duplicação e torna seu código mais composável.</p>
<h3>Interfaces Vazias e Flexibilidade</h3>
<p>A interface vazia <code>interface{}</code> em Go é especial: todo tipo a implementa automaticamente. Quando você embutir <code>interface{}</code> em uma interface customizada, você cria um tipo que pode lidar com qualquer coisa. Isso deve ser usado com cuidado, pois reduz segurança de tipos, mas é poderoso em situações onde você precisa de máxima flexibilidade.</p>
<pre><code class="language-go">package main
import (
"fmt"
"reflect"
)
type Contenedor interface {
interface{}
Tipo() string
}
type Caixa struct {
valor interface{}
}
func (c Caixa) Tipo() string {
return reflect.TypeOf(c.valor).String()
}
func main() {
caixa := Caixa{valor: 42}
fmt.Println(caixa.Tipo()) // int
caixa2 := Caixa{valor: "texto"}
fmt.Println(caixa2.Tipo()) // string
}</code></pre>
<h2>Padrões Avançados: Casos de Uso Reais</h2>
<h3>Logging e Middleware com Embedding</h3>
<p>Um padrão comum é usar embedding para adicionar funcionalidades transversais como logging, validação ou autorização. Você embutir uma interface que representa a dependência e promove seus métodos no tipo externo.</p>
<pre><code class="language-go">package main
import (
"fmt"
"log"
)
type Servico interface {
Processar(id int) string
}
type ServicoReal struct{}
func (s ServicoReal) Processar(id int) string {
return fmt.Sprintf("Processando ID: %d", id)
}
type ServicoComLog struct {
Servico // Embutindo a interface
}
func (s ServicoComLog) Processar(id int) string {
log.Printf("Iniciando processamento com ID: %d\n", id)
resultado := s.Servico.Processar(id)
log.Printf("Resultado: %s\n", resultado)
return resultado
}
func Executar(srv Servico, id int) {
fmt.Println(srv.Processar(id))
}
func main() {
srvReal := ServicoReal{}
srvComLog := ServicoComLog{Servico: srvReal}
Executar(srvComLog, 123)
}</code></pre>
<p>Aqui, <code>ServicoComLog</code> embutir a interface <code>Servico</code>, permitindo que você decore qualquer implementação com logging. O padrão Decorator é implementado naturalmente através do embedding.</p>
<h3>Extensão de Tipos Terceirizados</h3>
<p>Às vezes, você precisa estender o comportamento de um tipo que não pode ser modificado (porque vem de uma biblioteca externa). Você pode embutir esse tipo em uma nova struct e adicionar métodos.</p>
<pre><code class="language-go">package main
import (
"fmt"
"time"
)
type Relogio struct {
time.Time
}
func (r Relogio) Formatado() string {
return r.Format("02/01/2006 15:04:05")
}
func main() {
agora := Relogio{Time: time.Now()}
fmt.Println(agora.Formatado())
fmt.Println(agora.Year()) // Método promovido de time.Time
}</code></pre>
<p>Este padrão é extremamente útil quando você precisa adicionar métodos a tipos que não controla.</p>
<h2>Conclusão</h2>
<p>Embedding é um dos pilares da filosofia de design de Go e oferece uma alternativa elegante à herança tradicional. Primeiro, <strong>structs embutidas promovem campos e métodos automaticamente</strong>, permitindo composição clara sem a complexidade de hierarquias de classes. Segundo, <strong>interfaces embutidas permitem composição de comportamentos</strong>, facilitando a criação de abstrações modulares e testáveis. Terceiro, <strong>o padrão é flexível o suficiente para decoradores, middleware e extensão de tipos</strong>, resolvendo problemas práticos com simplicidade.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://golang.org/doc/effective_go#embedding" target="_blank" rel="noopener noreferrer">Effective Go - Embedding</a></li>
<li><a href="https://golang.org/ref/spec#Struct_types" target="_blank" rel="noopener noreferrer">The Go Programming Language - Structs</a></li>
<li><a href="https://research.swtch.com/interfaces" target="_blank" rel="noopener noreferrer">Go Interfaces - Russ Cox</a></li>
<li><a href="https://dave.cheney.net/2015/10/31/compiler-optimisation-tips-for-c-developers" target="_blank" rel="noopener noreferrer">Composing Simple Types in Go - Dave Cheney</a></li>
</ul>
<p><!-- FIM --></p>