Als een gebruikersgedefinieerd type de methode
String() string
hat geïmplementeerd, wordt deze methode aangeroepen voor het verkrijgen van de stringweergave wanneer dit type wordt gebruikt in functies van fmt (zoals fmt.Println, fmt.Printf("%v"), in het logpakket).
Het is raadzaam om String() te implementeren voor gebruikersgedefinieerde types, zodat je een zinvolle, menselijk leesbare uitvoer krijgt in plaats van de standaardvoorstelling van fmt (%v). Het is aan te bevelen om de uitvoer beknopt en toepasselijk te maken, en indien mogelijk veilig (zonder gevoelige gegevens te lekken).
Voorbeeld van implementatie:
type Order struct { ID string Amount int } func (o Order) String() string { return fmt.Sprintf("Order[%s]: %d", o.ID, o.Amount) } func main() { o := Order{"A123", 99} fmt.Println(o) } // Output: Order[A123]: 99
Als de methode met fouten of inadequaat is geïmplementeerd, kan dit leiden tot logs met betekenisloze of gevaarlijke uitvoer, wat het vinden van bugs bemoeilijkt.
Wat als je type de String() methode implementeert, maar je het als een pointer gebruikt en niet als waarde? Wordt String() aangeroepen?
Antwoord: De String() methode wordt aangeroepen als deze is geïmplementeerd voor het pointertype. Als deze alleen op waarde is geïmplementeerd, maar in de code het type een pointer is, wordt de methode aangeroepen dankzij het automatisch dereferenceren van Go voor methoden zonder pointer receiver. Dit is meestal geen probleem, maar als de methode alleen op pointer receiver is geïmplementeerd en je roept deze aan voor een waarde, zul je een compilatiefout krijgen.
Voorbeeld:
type X struct{} func (x *X) String() string { return "ptr" } fmt.Println(X{}) // fout: X implementeert String niet fmt.Println(&X{}) // ok, de methode wordt aangeroepen
Verhaal
In een groot project implementeerde het fouttype String() alleen op pointer receiver (
func (err *MyErr) String() string). Hierdoor verscheen bij het retourneren van de foutwaarde (geen pointer) in de logs een nutteloos{}in plaats van een nuttig bericht. De bug werd lang niet opgemerkt.
Verhaal
Een van de types bevatte gevoelige gegevens, en vanwege een foutieve implementatie van String() (de velden werden expliciet weergegeven) begonnen gebruikerswachtwoorden in de productie logs te verschijnen. Een veiligheidsaudit was nodig.
Verhaal
Het gebruik van automatische generatie van String() leidde ertoe dat bij het bijwerken van de structuur het nieuwe uitvoerformaat niet overeenkwam met het vorige, de logs werden onleesbaar en de parsing van logs door externe systemen werd verstoord.