Da trilha de Go Este conceito ainda não saiu como card do dia. ir para o card de hoje

Go Tipos Intermediário

Embedding e composição

Em Go, não há herança de classes. Em vez disso, usamos composição e embedding de structs para reutilizar código e criar tipos mais complexos. O embedding permite que um tipo incorpore outro, promovendo automaticamente os campos e métodos do tipo embutido para o tipo externo.

Quando você embute um tipo em uma struct, os métodos do tipo embutido passam a fazer parte do conjunto de métodos do tipo externo. Isso é chamado de promoção de métodos. Assim, você pode chamar métodos do tipo embutido diretamente no tipo externo, como se fossem dele.

O embedding é uma forma de composição: o tipo externo tem um tipo embutido, não é um tipo embutido. Isso evita os problemas de hierarquias profundas de herança e favorece a flexibilidade.

Neste card, veremos como criar structs que embutem outras structs, como os métodos são promovidos e por que isso é preferível à herança tradicional.

Pontos-chave

  • Embedding de structs promove campos e métodos do tipo embutido para o tipo externo.
  • Métodos promovidos podem ser chamados diretamente no tipo externo.
  • Composição expressa relação 'tem um', enquanto herança expressa 'é um'.
  • É possível sobrescrever métodos promovidos definindo um método com o mesmo nome no tipo externo.
  • Embedding também pode ser usado com interfaces para compor comportamentos.
embedding.go
package main

import "fmt"

// Animal é um tipo base com um método.
type Animal struct {
	Nome string
}

func (a Animal) Falar() {
	fmt.Printf("%s faz um som\n", a.Nome)
}

// Cachorro embute Animal. Os métodos de Animal são promovidos.
type Cachorro struct {
	Animal // embedding
	Raca   string
}

// Método próprio do Cachorro.
func (c Cachorro) Latir() {
	fmt.Printf("%s late: Au Au!\n", c.Nome)
}

func main() {
	// Criando um Cachorro com embedding.
	c := Cachorro{
		Animal: Animal{Nome: "Rex"},
		Raca:   "Labrador",
	}

	// Chamando método promovido de Animal.
	c.Falar() // Rex faz um som

	// Chamando método próprio.
	c.Latir() // Rex late: Au Au!

	// Acessando campo promovido.
	fmt.Println("Nome:", c.Nome) // Nome: Rex
	fmt.Println("Raça:", c.Raca) // Raça: Labrador
}

Exercícios

  1. 1
    Fácil

    Embedding básico

    Crie uma struct Pessoa com campos Nome e Idade. Depois, crie uma struct Funcionario que embuta Pessoa e tenha um campo Cargo. No main, instancie um Funcionario e imprima o nome, a idade e o cargo usando os campos promovidos.

    Resolver
  2. 2
    Médio

    Promoção de métodos

    Crie uma struct Motor com um método Ligar() que imprime "Motor ligado". Crie uma struct Carro que embuta Motor e tenha um método Andar() que imprime "Carro andando". No main, instancie um Carro e chame tanto Ligar() quanto Andar() diretamente no carro.

    Resolver
  3. 3
    Desafio

    Composição com interfaces e sobrescrita

    Crie uma interface Falante com o método Falar() string. Crie uma struct Animal que implementa Falar() retornando "Som genérico". Crie uma struct Gato que embuta Animal e sobrescreva Falar() retornando "Miau". No main, crie um slice de Falante contendo um Animal e um Gato, e imprima o resultado de Falar() para cada um.

    Resolver

Continue estudando