Vai al contenuto
eLearner.app
Modulo 5 · Lezione 2 di 522/50 nel corso~14 min
Lezioni del modulo (2/5)

Metodi: receiver value vs pointer

Un metodo in Go è una funzione con un receiver: un parametro speciale dichiarato fra func e il nome del metodo, che lega il metodo a un tipo. Non esistono classi: i metodi possono essere definiti su qualunque tipo nominato dichiarato nel package corrente.

Sintassi

Go
type Person struct {
    Name string
}

func (p Person) Greet() string {
    return "ciao " + p.Name
}

p := Person{Name: "Ada"}
fmt.Println(p.Greet())   // "ciao Ada"

Il receiver p Person rende Greet un metodo di Person. Dentro al metodo, p è una variabile come le altre.

Value receiver vs pointer receiver

Go
// VALUE receiver: opera su una COPIA del valore
func (p Person) NameUpper() string {
    return strings.ToUpper(p.Name)
}

// POINTER receiver: opera sul valore originale, può mutarlo
func (p *Person) Rename(n string) {
    p.Name = n
}

Con il pointer receiver puoi modificare il receiver e i cambiamenti si vedono fuori dal metodo. Con il value receiver no — modificheresti solo la copia locale.

Go
p := Person{Name: "Ada"}
p.Rename("Grace")
fmt.Println(p.Name)   // "Grace" — modifica visibile

Quando usare pointer receiver

Regole pratiche, in ordine di priorità:

  1. Devi modificare il receiver → pointer receiver. Obbligatorio.
  2. La struct è grande (decine di campi, array dentro) → pointer receiver per evitare copie costose.
  3. Coerenza: se ALMENO un metodo del tipo ha pointer receiver, usa pointer receiver anche per gli altri. Convenzione molto importante per le interfacce (Modulo 6).
  4. Tipi piccoli, immutabili, "valore" (time.Time, complex numbers, piccole struct) → value receiver, leggibile.

Metodi su tipi non-struct

Puoi definire metodi su qualunque tipo NOMINATO dichiarato nel tuo package:

Go
type Celsius float64

func (c Celsius) ToFahrenheit() float64 {
    return float64(c)*9/5 + 32
}

t := Celsius(20)
fmt.Println(t.ToFahrenheit())  // 68

Non puoi definirli su tipi di altri package (es. int, string): devi prima creare un tipo nominato locale.

Prova tu

Esercizio#go.m5.l2.e1
Tentativi: 0Caricamento…

Aggiungi a Person un metodo Greet() string (value receiver) che ritorna 'ciao <Name>'.

Caricamento editor…
Mostra suggerimento

Receiver tra parentesi PRIMA del nome del metodo.

Soluzione disponibile dopo 3 tentativi

Esercizio#go.m5.l2.e2
Tentativi: 0Caricamento…

Aggiungi un metodo Rename(n string) con POINTER receiver che cambia p.Name.

Caricamento editor…
Mostra suggerimento

Pointer receiver: `(p *Person)`.

Soluzione disponibile dopo 3 tentativi

Quiz#go.m5.l2.e3
Pronto

Quando usare un pointer receiver (p *T)?

Go
func (t ?T) M() { ... }
Opzioni di risposta

Recap

  • Metodo = funzione con un receiver: func (r T) Nome(...) ... { ... }.
  • Value receiver: opera su copia; Pointer receiver: opera sull'originale.
  • Go fa la conversione T*T automaticamente nella chiamata.
  • Pointer receiver quando: modifica + struct grande + coerenza con altri metodi del tipo.
  • Mai mischiare value e pointer receiver sullo stesso tipo.
  • I metodi vanno su tipi NOMINATI nel package corrente (anche non-struct).