Ricevitore e Interfaccia

I metodi con ricevitori di valore possono essere chiamati utilizzando sia i valori che i puntatori.

I metodi con ricevitori di puntatore possono essere chiamati solo utilizzando puntatori o valori indirizzabili.

Per esempio,

type S struct {
  data string
}

func (s S) Leggi() string {
  return s.data
}

func (s *S) Scrivi(str string) {
  s.data = str
}

sVals := map[int]S{1: {"A"}}

// Puoi chiamare Leggi solo utilizzando un valore
sVals[1].Leggi()

// Questo non compilerà:
// sVals[1].Scrivi("test")

sPtrs := map[int]*S{1: {"A"}}

// Sia i metodi Leggi che Scrivi possono essere chiamati utilizzando un puntatore
sPtrs[1].Leggi()
sPtrs[1].Scrivi("test")

Allo stesso modo, anche se un metodo ha un ricevitore di valore, può soddisfare un'interfaccia utilizzando un ricevitore di puntatore.

type F interface {
  f()
}

type S1 struct{}

func (s S1) f() {}

type S2 struct{}

func (s *S2) f() {}

s1Val := S1{}
s1Ptr := &S1{}
s2Val := S2{}
s2Ptr := &S2{}

var i F
i = s1Val
i = s1Ptr
i = s2Ptr

// Il seguente codice non compilerà perché s2Val è un valore e il metodo f di S2 non ha un ricevitore di valore
// i = s2Val

Effective Go contiene ottime spiegazioni su puntatori vs. valori.

Note aggiuntive:

  • Un tipo può avere un insieme di metodi con ricevitori di valore e un insieme di metodi con ricevitori di puntatore
    • L'insieme di metodi con ricevitori di valore è un sottoinsieme dell'insieme di metodi con ricevitori di puntatore, ma non viceversa
  • Regole
    • Gli oggetti valore possono utilizzare solo l'insieme di metodi con ricevitori di valore
    • Gli oggetti puntatore possono utilizzare l'insieme di metodi con ricevitori di valore + l'insieme di metodi con ricevitori di puntatore
  • Corrispondenza dell'interfaccia (o implementazione)
    • Il tipo corrisponde all'interfaccia se implementa tutti i metodi dell'interfaccia
    • In particolare, è necessario o che l'insieme di metodi valore del tipo corrisponda all'interfaccia o che l'insieme di metodi puntatore corrisponda all'interfaccia

Esistono due tipi specifici di corrispondenza:

  • L'insieme di metodi valore che corrisponde all'interfaccia
    • Va bene assegnare un oggetto valore o puntatore a una variabile di interfaccia poiché entrambi contengono l'insieme di metodi valore
  • L'insieme di metodi puntatore che corrisponde all'interfaccia
    • Solo un oggetto puntatore può essere assegnato a una variabile di interfaccia poiché solo l'insieme di metodi puntatore corrisponde all'interfaccia
    • Se viene assegnato un oggetto valore a una variabile di interfaccia, attiverà un meccanismo di controllo della vitalità dell'interfaccia durante la compilazione

Perché i = s2Val genera un errore, è perché l'insieme di metodi valore e l'interfaccia non corrispondono.