Salt la conținutul principal
Modulul 6 · Lecția 4 din 529/50 în curs~10 min
Lecții din modul (4/5)

Interfața Stringer

fmt.Stringer este probabil cea mai folosită interfață standard din toate Biblioteca standard a lui Go. Este demonstrația perfectă a puterii de interfețe mici.

Definiţie

Go
type Stringer interface {
    String() string
}

O singură semnătură. Orice tip care definește String() string satisface ea. Și fmt recunoaște această interfață: când îi transmiteți o valoare către fmt.Print*, dacă implementează Stringer, rezultatul String() este utilizat în locul reprezentării implicite.

Exemplu

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)

Aceeași valoare se imprimă cu formatare personalizată în %v, %s, Println, Sprint, log etc. Toate doar prin definirea unei singure metode.

Când are sens

  • Tipuri care modelează un domeniu (ID-uri, coduri, coordonate, enumerari).
  • Erori cu o reprezentare care poate fi citită de om (vezi următoarea lecție despre error).
  • Tipuri pe care le înregistrați des și pentru care doriți un format fix.

Nu pentru toate: dacă tipul este simplu și reprezentarea implicită este în regulă, nu adăugați zgomot.

Tipuri de enumerare: model comun cu 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

Fără String(), fmt.Println(OK) ar tipări 0. Cu String(), imprimă numele simbolic. stringer instrumentul generează acest model automat.

Atenție la recursiunea infinită

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

Stringer pe un receptor pointer

Dacă String() are un receptor pointer, numai *T satisface Stringer. Cu fmt.Println(t) (o valoare), Go se uită la setul de metode T, nu îl găsește și folosește formatul implicit. Pentru a evita acest lucru, valoare receptor este de obicei folosit pentru String() (este o „vizualizare”; nu modifica orice).

Încearcă

Exercițiu#go.m6.l4.e1
Încercări: 0Se încarcă…

Implementați String() pe Point astfel încât să returneze (X,Y).

Se încarcă editorul...
Afișează indiciu

Utilizați `fmt.Sprintf` pentru a formata câmpurile.

Soluție disponibilă după 3 încercări

Exercițiu#go.m6.l4.e2
Încercări: 0Se încarcă…

Implementați String() pe un tip Status (int): 0 → „OK”, 1 → „WARN”, în caz contrar → „ERR”.

Se încarcă editorul...
Afișează indiciu

Porniți valoarea receptorului; nu uitați să furnizați o valoare implicită.

Soluție disponibilă după 3 încercări

Quiz#go.m6.l4.e3
Gata

Ce semnătură trebuie să aibă metoda pentru a satisface fmt.Stringer?

Go
func (x T) ??? {}
Opțiuni de răspuns

Recapitulare

  • fmt.Stringer = interface { String() string }.
  • Implementarea acestuia modifică modul în care fmt.Print* reprezintă tipul.
  • Idiomatic pentru enumerari (iota), tipuri de domenii, coduri/identificatori.
  • Nu apelați niciodată fmt.Sprintf("%s", t) pe t în interiorul String() (recursiune).
  • Convenție: receptor de valoare pentru String() (fără mutație, evită „surprizele stabilite prin metoda”).