Direct naar de hoofdinhoud
Module 6 · Les 4 van 529/50 in de cursus~10 min
Modulelessen (4/5)

De Stringer-interface

fmt.Stringer is waarschijnlijk de meest gebruikte standaardinterface van allemaal Go's standaardbibliotheek. Het is de perfecte demonstratie van de kracht van kleine interfaces.

Definitie

Go
type Stringer interface {
    String() string
}

Eén enkele handtekening. Elk type dat String() string definieert, voldoet het. En fmt herkent deze interface: wanneer u een waarde doorgeeft aan fmt.Print*, als Stringer wordt geïmplementeerd, het resultaat van String() wordt gebruikt in plaats van de standaardweergave.

Voorbeeld

Go
type Point struct{ X, Y int }

func (p Point) String() string {
    return fmt.Sprintf("(%d,%d)", p.X, p.Y)
}

fmt.Println(Point{1, 2})              // (1,2)
fmt.Printf("%v %s\n", Point{3, 4}, Point{5, 6})
// (3,4) (5,6)

Dezelfde waarde wordt afgedrukt met aangepaste opmaak in %v, %s, Println, Sprint, log, enz. Allemaal door slechts één methode te definiëren.

Wanneer het zinvol is

  • Typen die een domein modelleren (ids, codes, coördinaten, opsommingen).
  • Fouten met een voor mensen leesbare weergave (zie volgende les over error).
  • Typen die u vaak logt en waarvoor u een vast formaat wilt.

Niet voor alles: als het type eenvoudig is en de standaardweergave is prima, voeg geen ruis toe.

Enum-typen: algemeen patroon met iota

Go
type Status int

const (
    OK Status = iota
    WARN
    ERR
)

func (s Status) String() string {
    switch s {
    case OK:   return "OK"
    case WARN: return "WARN"
    case ERR:  return "ERR"
    default:   return "UNKNOWN"
    }
}

fmt.Println(OK, WARN, ERR)   // OK WARN ERR

Zonder String() zou fmt.Println(OK) 0 afdrukken. Met String(), het drukt de symbolische naam af. De stringer tool genereert dit patroon automatisch.

Pas op voor oneindige recursie

Go
type T int
func (t T) String() string {
    return fmt.Sprintf("%d", int(t))  // OK: cast to int breaks the recursion
}

Stringer op een aanwijzerontvanger

Als String() een pointerontvanger heeft, voldoet alleen *T aan Stringer. Met fmt.Println(t) (een waarde) kijkt Go naar de methodenset van T, kan het niet vinden en gebruikt het standaardformaat. Om dit te voorkomen, gebruikt u value ontvanger wordt meestal gebruikt voor String() (het is een "weergave"; dat is niet het geval iets aanpassen).

Probeer het

Oefening#go.m6.l4.e1
Pogingen: 0Laden…

Implementeer String() op Point zodat het (X,Y) retourneert.

Editor laden…
Toon hint

Gebruik `fmt.Sprintf` om de velden op te maken.

Oplossing beschikbaar na 3 pogingen

Oefening#go.m6.l4.e2
Pogingen: 0Laden…

Implementeer String() op een type Status (int): 0 → 'OK', 1 → 'WARN', anders → 'ERR'.

Editor laden…
Toon hint

Schakel de waarde van de ontvanger in; Vergeet niet een standaardinstelling op te geven.

Oplossing beschikbaar na 3 pogingen

Quiz#go.m6.l4.e3
Klaar

Welke handtekening moet de methode hebben om aan fmt.Stringer te voldoen?

Go
func (x T) ??? {}
Antwoordmogelijkheden

Samenvatten

  • fmt.Stringer = interface { String() string }.
  • Door het te implementeren verandert de manier waarop fmt.Print* het type vertegenwoordigt.
  • Idiomatisch voor enums (iota), domeintypen, codes/identifiers.
  • Bel nooit fmt.Sprintf("%s", t) op t binnen String() (recursie).
  • Conventie: waardeontvanger voor String() (geen mutatie, vermijdt "methode-set verrassingen").