Przejdź do głównej treści
eLearner.app
Moduł 6 · Lekcja 4 z 529/50 w kursie~10 min
Lekcje modułu (4/5)

Interfejs Stringer

fmt.Stringer jest prawdopodobnie najczęściej używanym standardowym interfejsem we wszystkich Standardowa biblioteka Go. To idealna demonstracja mocy małych interfejsów.

Definicja

Go
type Stringer interface {
    String() string
}

Pojedynczy podpis. Każdy typ definiujący String() string spełnia wymagania to. A fmt rozpoznaje ten interfejs: kiedy przekazujesz wartość do fmt.Print*, jeśli implementuje Stringer, wynik String() jest używany zamiast reprezentacji domyślnej.

Przykład

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)

Ta sama wartość jest drukowana z niestandardowym formatowaniem w %v, %s, Println, Sprint, log, itd. Wszystko poprzez zdefiniowanie jednej metody.

Kiedy ma to sens

  • Typy modelujące domenę (identyfikatory, kody, współrzędne, wyliczenia).
  • Błędy w reprezentacji czytelnej dla człowieka (patrz następna lekcja na temat error).
  • Typy, które często logujesz i dla których chcesz mieć stały format.

Nie do wszystkiego: jeśli typ jest prosty i jest to domyślna reprezentacja jest w porządku, nie dodawaj hałasu.

Typy wyliczeniowe: wspólny wzorzec z 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

Bez String(), fmt.Println(OK) wydrukowałoby 0. Z String(), wypisuje symboliczną nazwę. stringer narzędzie automatycznie generuje ten wzór.

Uważaj na nieskończoną rekurencję

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

Stringer na odbiorniku wskaźnika

Jeśli String() ma odbiornik wskaźnika, tylko *T spełnia wymagania Stringer. W przypadku fmt.Println(t) (wartości) Go sprawdza zestaw metod T, nie znajduje go i używa formatu domyślnego. Aby tego uniknąć, wartość odbiornik jest zwykle używany dla String() (jest to „widok”; tak nie jest modyfikować cokolwiek).

Spróbuj

Ćwiczenie#go.m6.l4.e1
Próby: 0Ładowanie...

Zaimplementuj String() w punkcie, aby zwracał (X, Y).

Ładowanie edytora...
Pokaż wskazówkę

Użyj `fmt.Sprintf`, aby sformatować pola.

Rozwiązanie dostępne po 3 próbach

Ćwiczenie#go.m6.l4.e2
Próby: 0Ładowanie...

Zaimplementuj String() dla typu Status (int): 0 → „OK”, 1 → „WARN”, w przeciwnym razie → „ERR”.

Ładowanie edytora...
Pokaż wskazówkę

Włącz wartość odbiornika; pamiętaj o podaniu wartości domyślnej.

Rozwiązanie dostępne po 3 próbach

Quiz#go.m6.l4.e3
Gotowe

Jaki podpis musi posiadać metoda, aby spełnić wymagania fmt.Stringer?

Go
func (x T) ??? {}
Opcje odpowiedzi

Podsumowanie

  • KODEF0.
  • Implementacja zmienia sposób, w jaki fmt.Print* reprezentuje typ.
  • Idiomatyczny dla wyliczeń (iota), typów domen, kodów/identyfikatorów.
  • Nigdy nie wywołuj fmt.Sprintf("%s", t) na t wewnątrz String() (rekurencja).
  • Konwencja: odbiorca wartości dla String() (bez mutacji, pozwala uniknąć „niespodzianek związanych z zestawem metod”).