0Pricing
Go Academy · Lezione

Receiver per puntatori nei metodi

Modificare lo stato di una struct tramite receiver per puntatore

Receiver per puntatori nei metodi è una lezione Go Academy gratuita su CoddyKit. Questa è la lezione 3 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Go Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Go Academy include 4 lezioni in totale.

Riepilogo: ricevitore per valore e ricevitore puntatore

Un ricevitore per valore opera su una copia della struct. Un ricevitore puntatore opera sull'originale. Usi ricevitori puntatore ogni volta che un metodo deve modificare lo stato.

Modifica con un ricevitore puntatore

Solo un ricevitore puntatore può modificare la struct:

package main
import "fmt"

type Stack struct{ items []int }

func (s *Stack) Push(v int) { s.items = append(s.items, v) }
func (s *Stack) Pop() int {
    n := len(s.items) - 1
    v := s.items[n]
    s.items = s.items[:n]
    return v
}

func main() {
    var st Stack
    st.Push(1); st.Push(2)
    fmt.Println(st.Pop()) // 2
}

Regola di coerenza

Se un qualsiasi metodo di un tipo richiede un ricevitore puntatore, tutti i metodi dovrebbero usare ricevitori puntatore. La combinazione dei due tipi causa problemi con la soddisfazione delle interfacce:

package main
import "fmt"

type Counter struct{ n int }

func (c *Counter) Inc()   { c.n++ }   // pointer
func (c *Counter) Val() int { return c.n } // pointer too

func main() {
    c := &Counter{}
    c.Inc(); c.Inc()
    fmt.Println(c.Val()) // 2
}

Soddisfazione delle interfacce

Un metodo con ricevitore puntatore appartiene all'insieme dei metodi di *T, ma non a quello di T. Questo influisce sulla soddisfazione delle interfacce:

package main
import "fmt"

type Writer interface{ Write([]byte) }

type File struct{ name string }
func (f *File) Write(b []byte) { fmt.Println(string(b)) }

func main() {
    var w Writer = &File{"out.txt"} // OK
    // var w Writer = File{} — compile error
    w.Write([]byte("hello"))
}

Presa automatica dell'indirizzo

Go prende automaticamente l'indirizzo quando si chiama un metodo con ricevitore puntatore su un valore indirizzabile:

package main
import "fmt"

type Box struct{ V int }
func (b *Box) Double() { b.V *= 2 }

func main() {
    b := Box{5}
    b.Double()          // Go does (&b).Double()
    fmt.Println(b.V)    // 10
}

Valori non indirizzabili

Non è possibile chiamare metodi con ricevitore puntatore su valori non indirizzabili (elementi di map, valori restituiti da funzioni non assegnati a variabili):

package main

type T struct{ V int }
func (t *T) Set(v int) { t.V = v }

func getT() T { return T{} }

func main() {
    var t T
    t.Set(1)       // OK — t is addressable
    // getT().Set(1) — ERROR: cannot take address of getT()
    _ = t
}

Ricevitori per struct di grandi dimensioni

Usi sempre ricevitori puntatore per le struct di grandi dimensioni, così da evitare copie costose a ogni chiamata di metodo:

package main

type Image struct{ pixels [1024][1024]uint8 }

// Value receiver copies 1MB per call!
func (img Image) Bad() uint8 { return img.pixels[0][0] }

// Pointer receiver — zero copy
func (img *Image) Good() uint8 { return img.pixels[0][0] }

func main() { _ = Image{} }

Ricevitori puntatore nil

I metodi con ricevitori puntatore possono gestire nil senza errori:

package main
import "fmt"

type List struct{ head *node }
type node struct{ val int; next *node }

func (l *List) Len() int {
    if l == nil { return 0 }
    count := 0
    for n := l.head; n != nil; n = n.next { count++ }
    return count
}

func main() {
    var l *List
    fmt.Println(l.Len()) // 0
}

Embedding e ricevitori puntatore

Quando si incorpora un tipo con ricevitori puntatore, anche la struct esterna deve essere usata come puntatore per ottenere i metodi promossi:

package main
import "fmt"

type Base struct{ V int }
func (b *Base) Set(v int) { b.V = v }

type Derived struct{ Base }

func main() {
    d := &Derived{}
    d.Set(42)           // promoted pointer-receiver method
    fmt.Println(d.V)    // 42
}

Copia delle mutex

Non copi mai una struct che contiene una sync.Mutex: usi sempre un ricevitore puntatore o passi la struct tramite puntatore. Copiare una mutex bloccata provoca un deadlock:

package main
import "sync"

type Safe struct {
    mu sync.Mutex
    v  int
}

// Correct: pointer receiver
func (s *Safe) Set(v int) {
    s.mu.Lock()
    defer s.mu.Unlock()
    s.v = v
}

func main() { _ = Safe{} }

go vet rileva gli errori

Esegua go vet ./... per rilevare errori comuni relativi ai ricevitori puntatore, come la copia di mutex e lock. Fa parte delle pipeline di go build e dei controlli CI.

Verifica rapida

Nell'insieme dei metodi di quali tipi si trova un metodo con ricevitore puntatore?

Riepilogo

Punti chiave:

  • I ricevitori puntatore modificano lo stato; i ricevitori per valore no
  • Mantenga lo stesso tipo di ricevitore per tutti i metodi di un tipo
  • Solo *T soddisfa le interfacce che richiedono metodi con ricevitore puntatore
  • Non copi mai struct con mutex: usi ricevitori puntatore

Esercizio

Implementi una struct Queue con i metodi Enqueue(int), Dequeue() (int, bool) e Len() int, tutti con ricevitore puntatore e basati su una slice []int.

Domande Frequenti

La lezione «Receiver per puntatori nei metodi» è gratuita?

Sì — il testo completo di «Receiver per puntatori nei metodi» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Go Academy, passa a CoddyKit PRO. Il corso Go Academy include 4 lezioni in totale.

Cosa imparerò in «Receiver per puntatori nei metodi»?

Modificare lo stato di una struct tramite receiver per puntatore Eserciti Go Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Go Academy?

Non è richiesta alcuna esperienza precedente. Go Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 4.

Quanto tempo richiede la lezione «Receiver per puntatori nei metodi»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Go Academy?

Sì. Ogni lezione Go Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Che cosa sono i puntatori?
  2. Puntatori e funzioni
  3. Receiver per puntatori nei metodi
  4. new() e quando utilizzare i puntatori
← Torna a Go Academy