Storia della domanda:
In Go si verificano spesso situazioni in cui i tipi incorporati non sono sufficienti e è necessario definire un proprio tipo di dati con metodi per incapsulare la logica e ampliare la funzionalità. Questo si ottiene creando tipi personalizzati (type) e metodi (func (r Receiver) MethodName()).
Problema:
I programmatori principianti spesso si confondono — quali sono le differenze tra la dichiarazione di un nuovo tipo basato su uno esistente? Come implementare correttamente i metodi? Come si gestisce la questione della copia, del passaggio per valore/riferimento? Sbagliano nell'ambito della visibilità, del receiver del tipo e del lavoro con le strutture incorporate.
Soluzione:
Per definire un proprio tipo si utilizza la parola chiave type. I metodi sono implementati utilizzando il receiver (ricevitore) — questo è importante per lavorare con le interfacce.
Esempio di codice:
type MyInt int func (m MyInt) Double() int { return int(m) * 2 } // Per le strutture: type User struct { Name string Age int } func (u *User) Birthday() { u.Age++ } var u = User{"Alice", 30} u.Birthday() // Age = 31
Caratteristiche chiave:
I tipi personalizzati ereditano i metodi del tipo di base?
No. Se si definisce type MyInt int, allora MyInt non ha metodi int. Ad esempio, non funzionerà la chiamata a String() o ad altri metodi del tipo di base.
È possibile definire metodi per alias di tipo?
Per alias (type MyType = ExistingType) non è possibile aggiungere metodi. I metodi sono definiti solo per nuovi tipi (type MyType ExistingType), e non per i soprannomi.
Quale receiver utilizzare: puntatore o valore?
Se il metodo deve modificare un oggetto, è meglio utilizzare un puntatore. Il value receiver copia la struttura, il che può portare a comportamenti inaspettati, se ad esempio la struttura contiene campi-slice e mappe.
Esempio di codice:
type Counter struct { value int } func (c *Counter) Inc() { c.value++ } func main() { c := Counter{} c.Inc() // solo con il puntatore il metodo modificherà value }
Un programmatore ha creato type MySlice []int e si aspettava che i metodi []int, ad esempio, append, funzionassero come metodi sul tipo MySlice. Alla fine si è scoperto che non ci sono metodi e non è possibile accedere a MySlice come a []int direttamente.
Pro:
Contro:
È stato definito type Counter int con il metodo Inc, il che ha permesso di utilizzarlo in diverse parti del programma con logica comune e senza codice ripetuto.
Pro:
Contro: