Lekcje modułu (1/5)
Zaawansowane `fmt`
Pakiet fmt jest bramą do wszystkich tekstowych operacji we/wy w Go. Dobra znajomość oznacza pisanie czytelnych dzienników, błędów informacyjnych i idiomatyczne formatowanie wartości bez uciekania się do zewnętrznych bibliotek.
Cztery rodziny
fmt udostępnia funkcje w czterech rodzinach, rozróżnianych przedrostkiem:
Print*→ zapisuje doos.Stdout(Print,Println,Printf).Fprint*→ zapisuje do dowolnegoio.Writer(Fprintln(os.Stderr, ...),Fprintf(file, ...)).Sprint*→ zwraca string bez drukowania (os.Stdout0,os.Stdout1).os.Stdout2 → buduje sformatowanyos.Stdout3.
fmt.Println("hello") // stdout
fmt.Fprintln(os.Stderr, "boom") // stderr
s := fmt.Sprintf("[%d]", 42) // "[42]"
err := fmt.Errorf("parse %q: %w", in, base) // wrapped errorRóżnica pomiędzy Print i Println polega jedynie na spacji pomiędzy argumentami a końcowym znakiem nowej linii: Println zawsze dodaje , Print nie, Printf stosuje się do formatu.
Główne czasowniki
| Czasownik | Co to robi |
|---|---|
| KODEF0 | Wartość domyślna (wywołuje String(), jeśli jest zaimplementowana). |
| KODEF2 | Struktura z nazwami pól. |
| KODEF3 | Składnia Go (przydatna przy debugowaniu i migawkach). |
| KODEF4 | Dynamiczny typ wartości. |
| KODEF5 | Liczba całkowita o podstawie 10. |
| KODEF6 | Binarny, ósemkowy, szesnastkowy (małe/wielkie litery). |
| KODEF7 | Zmiennoprzecinkowy: stały, wykładniczy, zwarty. |
| KODEF8 | Ciąg (lub error/String()0). |
| KODEF11 | Ciąg cytowany w stylu go (w tym znaki ucieczki). |
| KODEF12 | Znak Unicode (String()3). |
| KODEF14 | Wskaźnik w formacie szesnastkowym. |
| KODEF15 | Zawijanie błędów (tylko w String()6). |
type Point struct{ X, Y int }
p := Point{1, 2}
fmt.Printf("%v\n", p) // {1 2}
fmt.Printf("%+v\n", p) // {X:1 Y:2}
fmt.Printf("%#v\n", p) // main.Point{X:1, Y:2}
fmt.Printf("%T\n", p) // main.PointSzerokość, precyzja, flagi
Czasowniki numeryczne i łańcuchowe akceptują szerokość i precyzję:
%6d→ minimalna szerokość 6, lewe wypełnienie ze spacjami.%-6d→ szerokość 6, prawe wypełnienie (flaga-).%06d→ szerokość 6, wypełnienie0(flaga0).%.2f→ precyzja 2 cyfry dziesiętne.%8.2f→ szerokość 8, dokładność 2.
fmt.Printf("|%6d|\n", 42) // | 42|
fmt.Printf("|%-6d|\n", 42) // |42 |
fmt.Printf("|%06d|\n", 42) // |000042|
fmt.Printf("|%8.2f|\n", 3.14)// | 3.14|W przypadku tabel wyrównanych stała szerokość + %-...s dla kolumn tekstowych jest najprostszym wzorcem przed przejściem do text/tabwriter.
%w i zawijanie błędów
%w jest wyjątkowy: działa tylko wewnątrz fmt.Errorf i zachowuje oryginalny błąd w łańcuchu, dzięki czemu errors.Is i errors.As mogą go obejść.
if _, err := os.Open(path); err != nil {
return fmt.Errorf("read config %q: %w", path, err)
}Użycie %v zamiast %w wypisuje komunikat o błędzie, ale przerywa łańcuch: bez rozpakowywania, bez errors.Is. Reguła: jeśli chcesz, aby osoba wywołująca była w stanie rozróżnić rodzaj lub tożsamość błędu, użyj %w (tylko jeden na Errorf).
Ćwiczenia
Użyj fmt.Sprintf, aby sformatować ciąg „[42]” z liczby całkowitej 42, a następnie wydrukuj go.
Rozwiązanie dostępne po 3 próbach
Wydrukuj strukturę p z czasownikiem %+v (musi zawierać nazwy pól).
Rozwiązanie dostępne po 3 próbach
Który czasownik użyty w fmt.Errorf zachowuje łańcuch błędów dla błędów.Is/As?
err := fmt.Errorf("read %q: ???", path, base)