Aula 22 - Tutorial Golang - Embedding

Embedding

Go suporta a incorporação (Embedding) de estruturas e interfaces para expressar uma composição de tipos mais perfeita.

Incorporando Interface em Outra Interface

Uma interface pode embutir qualquer número de interfaces nela, assim como pode ser embutida em qualquer interface. Todos os métodos da interface incorporada tornam-se parte da interface. É uma maneira de criar uma nova interface mesclando algumas pequenas interfaces. Vamos entender com um exemplo. Suponha que temos um animal de interface como abaixo

type animal interface {
    breathe()
    walk()
}
Digamos que haja outra interface chamada human que incorpora a interface animal.

type human interface {
    animal
    speak()
}  
Então, se algum tipo precisa implementar a interface human, ele deve definir o método:
  • breathe() e walk() da interfaces animal, já que animal está embutido na human
  • E o método speak() da interface human

Código Incorporando Interface Em Outra Interface


package main

import "fmt"

type animal interface {
    breathe()
    walk()
}

type human interface {
    animal
    speak()
}

type employee struct {
    name string
}

func (e employee) breathe() {
    fmt.Println("Employee breathes")
}

func (e employee) walk() {
    fmt.Println("Employee walk")
}

func (e employee) speak() {
    fmt.Println("Employee speaks")
}

func main() {
    var h human

    h = employee{name: "John"}
    h.breathe()
    h.walk()
    h.speak()
    fmt.Println(h)
}

E pra executar é só entrar na pasta onde tá o arquivo embedding.go


go run embedding.go

Saída:

Employee breathes Employee walk Employee speaks {John}

Incorporando interface em uma estrutura

Uma interface também pode ser incorporada em uma estrutura. Todos os métodos da interface incorporada podem ser chamados por meio dessa estrutura. Como esses métodos serão chamados dependerá se a interface incorporada é um campo nomeado ou um campo sem nome/anônimo. Se a interface incorporada for um campo nomeado, os métodos da interface devem ser chamados por meio do nome da interface nomeada. Se a interface incorporada for um campo sem nome/anônimo, os métodos da interface podem ser referidos diretamente ou por meio do nome da interface. Vamos ver um programa ilustrando os pontos acima. Declaramos duas struct pet1 e pet2. A estrutura pet1 nomeou a interface animal nele.

type pet1 struct {
    a    animal
    name string
}
O pet2 tem uma interface de animal sem nome/anônima incorporada.

type pet2 struct {
    animal
    name string
}
Para uma instância da estrutura pet1, chamamos o método breath() e walk() assim:

p1.a.breathe()
p1.a.walk()
Chamando diretamente esses métodos vai dá erro de compilação.

//p1.breathe()
//p1.walk()

p1.breathe undefined (type pet1 has no field or method breathe)
p1.walk undefined (type pet1 has no field or method walk)
Para uma instância da estrutura pet2, podemos chamar o método breathe() e walk() como diretamente

p2.breathe()
p2.walk()
Podemos acessar diretamente os métodos da interface incorporada se a interface incorporada for anônima ou sem nome. O jeito abaixo também é válido para chamar interface incorporada sem nome/anônima.

p2.animal.breathe()
p2.animal.walk()
Observe também que, ao criar a instância da estrutura pet1 ou pet2, a interface incorporada, ou seja, animal, é inicializada com um tipo que a implementa, por exemplo, dog .

p1 := pet1{name: "Milo", a: d}
p2 := pet2{name: "Oscar", animal: d}
Se não inicializarmos a interface incorporada animal, ela será inicializada com o valor zero na interface que é nil. Chamar o método breath() e walk() em tal instância da estrutura pet1 ou pet2 criará um pânico.

Incorporando interface em uma estrutura


package main

import "fmt"

type animal interface {
    breathe()
    walk()
}

type dog struct {
    age int
}

func (d dog) breathe() {
    fmt.Println("Dog breathes")
}

func (d dog) walk() {
    fmt.Println("Dog walk")
}

type pet1 struct {
    a    animal
    name string
}

type pet2 struct {
    animal
    name string
}

func main() {
    d := dog{age: 5}
    p1 := pet1{name: "Milo", a: d}

    fmt.Println(p1.name)
    // p1.breathe()
    // p1.walk()
    p1.a.breathe()
    p1.a.walk()

    p2 := pet2{name: "Oscar", animal: d}
    fmt.Println(p2.name)
    p2.breathe()
    p2.walk()
    p1.a.breathe()
    p1.a.walk()
}

E pra executar é só entrar na pasta onde tá o arquivo embedding.go


go run embedding.go

Saída:

Milo Dog breathes Dog walk Milo Dog breathes Dog walk Dog breathes Dog walk

É isso pessoal, fico por aqui!

Até mais. :)

Página principal do blog

página do Código Fluente no Facebook

Esse é o link do código fluente no Pinterest

Meus links de afiliados:

Hostinger

Digital Ocean

One.com

Obrigado e bons estudos. ;)