In Go kunnen methoden worden gedeclareerd als zowel voor waarde als voor een pointer naar een type (value/pointer receiver). Deze functie is behouden sinds de vroege versies van de taal voor expliciete controle over wie de oorspronkelijke gegevens zal wijzigen. Het klassieke probleem is de noodzaak om een afstand te bewaren tussen de semantiek van waarde (kopie, wijzigt niet) en pointer (gemeenschappelijke toegang tot gegevens en de mogelijkheid tot modificatie).
Probleem — het is gemakkelijk om een fout te maken door een methode met een value receiver te declareren en niet het verwachte effect te krijgen, of door een value-methode aan te roepen op een pointer-variabele.
Oplossing — hou je aan de volgende regels:
Voorbeeldcode:
type Counter struct { Value int } func (c Counter) IncCopy() { c.Value++ } // value receiver func (c *Counter) IncPointer() { c.Value++ } // pointer receiver c := Counter{} c.IncCopy() // Value blijft 0 c.IncPointer() // Value wordt 1
Belangrijke kenmerken:
Kan een value receiver-methode op een pointer worden aangeroepen, en een pointer-methode op een waarde?
Go "onder de motorkap" dereferentieert automatisch pointers of neemt hun adres, dus de aanroep is toegestaan als de types compatibel zijn. Maar niet altijd — bij interfaces werkt dit niet altijd voorspelbaar.
var c Counter (&c).IncCopy() // Kan value-methode via pointer aanroepen c.IncPointer() // Kan pointer-methode aanroepen, Go neemt automatisch het adres
Wat gebeurt er als een structuur alleen pointer-methoden implementeert, maar deze via waarde naar een interface wordt doorgegeven?
Een dergelijk object implementeert de interface niet als het pointer-methoden vereist, wat kan leiden tot panic of een compilatiefout.
type D interface { IncPointer() } func f(d D) {} c := Counter{} f(c) // fout! Counter implementeert de interface niet via waarde f(&c) // correct
Zal de structuur veranderen bij het aanroepen van een methode van een pointer receiver, als een kopie van de pointer is doorgegeven?
Ja, zelfs als de pointer wordt gekopieerd, ligt er één en hetzelfde object onder, dus het resultaat zal hetzelfde zijn.
c := Counter{} p := &c p2 := p p2.IncPointer() // Value verhoogd
Een ingenieur implementeert een structuur met value receiver-methoden "Update". Door de interface wordt de structuur doorgegeven, maar wijzigingen verdwijnen — ze werken immers met een kopie.
Voordelen:
Nadelen:
Duidelijke overeenkomst binnen het team: alle methoden die de toestand wijzigen zijn alleen pointer receivers, interfaces worden alleen doorgegeven via pointers, value — voor "uitbreidingen" en hulpprogramma's.
Voordelen:
Nadelen: