Ce face embedding (încorporare)
Go nu are moștenire. În loc de ea, un struct poate încorpora alt tip scriind doar numele tipului, fără nume de câmp. Câmpurile și metodele tipului încorporat sunt „promovate”: a.Nume funcționează ca prescurtare pentru a.Persoana.Nume. Tipul exterior implementează astfel automat interfețele pe care le implementează cel încorporat.
Din Go 1.27, câmpurile promovate se pot da direct și în literal: Angajat{Nume: "Ana", Functie: "programator"}; înainte trebuia scris Angajat{Persoana: Persoana{Nume: "Ana"}, ...}. Dacă tipul exterior are un câmp sau o metodă cu același nume, aceasta o ascunde pe cea încorporată (dar ea rămâne accesibilă prin numele complet). Valoarea încorporată nu „știe” de tipul exterior: metodele ei lucrează doar pe partea ei.
Interfețele se pot și ele încorpora: type ReadWriter interface { Reader; Writer }. Un tip des încorporat este sync.Mutex, care adaugă metodele Lock și Unlock.
Exemple
Exemplul 1: Câmpuri și metode promovate
package main
import "fmt"
type Persoana struct {
Nume string
Oras string
}
func (p Persoana) Prezentare() string {
return p.Nume + " din " + p.Oras
}
type Angajat struct {
Persoana
Functie string
}
func main() {
a := Angajat{Persoana: Persoana{"Ana", "Iași"}, Functie: "programator"}
fmt.Println(a.Nume) // promovat
fmt.Println(a.Persoana.Oras) // nume complet
fmt.Println(a.Prezentare(), "-", a.Functie)
// Go 1.27: câmpurile promovate direct în literal
b := Angajat{Nume: "Radu", Oras: "Cluj", Functie: "tester"}
fmt.Printf("%+v\n", b)
}
Rezultat
Ana
Iași
Ana din Iași - programator
{Persoana:{Nume:Radu Oras:Cluj} Functie:tester}
Exemplul 2: Suprascriere și sync.Mutex încorporat
Angajat.Prezentare o ascunde pe cea a lui Persoana, dar o poate apela.
package main
import (
"fmt"
"sync"
)
type Persoana struct{ Nume string }
func (p Persoana) Prezentare() string { return "Sunt " + p.Nume }
type Angajat struct {
Persoana
Firma string
}
func (a Angajat) Prezentare() string {
return a.Persoana.Prezentare() + " și lucrez la " + a.Firma
}
type Contor struct {
sync.Mutex
vizite int
}
func main() {
a := Angajat{Persoana{"Mihai"}, "Dexblog"}
fmt.Println(a.Prezentare())
var c Contor
c.Lock()
c.vizite++
c.Unlock()
fmt.Println("vizite:", c.vizite)
}
Rezultat
Sunt Mihai și lucrez la Dexblog
vizite: 1
Greșeli frecvente
- Așteptarea unui comportament de moștenire: o metodă a lui
Persoanacare apeleazăp.Prezentare()folosește tot versiunea luiPersoana, nu pe cea a luiAngajat. - Același nume promovat din două tipuri încorporate:
ambiguous selector a.Nume. Folosește numele complet. - Încorporarea unui
sync.Mutexîntr-un tip exportat faceLock/Unlockpublice; pentru tipuri publice preferă un câmp cu nume (mu sync.Mutex).
Comenzi înrudite
struct și struct-uri: Grupează mai multe câmpuri cu nume și tipuri diferite într-un singur tip; baza pentru modelarea datelor în Go.metode: Funcții legate de un tip prin receptor; cu receptor pointer pot modifica valoarea pe care sunt apelate.interface și interfețe: Interfața descrie un set de metode; orice tip care le are o implementează automat, fără declarație explicită.