Menu

Printf i Sprintf w Go (Golang): ściągawka formatowania fmt

Jak pakiet fmt w Go wypisuje i formatuje wartości: Println, Printf, Sprintf i Errorf, pełna tabela czasowników formatujących (%v, %+v, %d, %s, %q, %f, %T, %w i inne), szerokość, precyzja i dopełnianie.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

Pakiet fmt ma trzy rodziny funkcji wypisujących, a każda rodzina ma te same trzy warianty:

FunkcjaDokąd trafia wynikFormat
Print, Println, Printfstandardowe wyjściedomyślny, domyślny ze spacjami i nową linią, string formatujący
Sprint, Sprintln, Sprintfzwracany stringte same trzy style
Fprint, Fprintln, Fprintfdowolny io.Writer (plik, bufor, odpowiedź HTTP)te same trzy style
Errorfzwracany errorstring formatujący plus %w do opakowywania

Println dodaje spacje między argumentami i nową linię na końcu. Printf nic nie dodaje: \n dopisujesz samodzielnie. Print dodaje spacje tylko między argumentami, z których żaden nie jest stringiem, co jest na tyle zaskakujące, że większość kodu używa Println lub Printf.

Czasowniki formatujące

Ogólne

CzasownikWypisujePrzykładowy wynik
%vwartość w domyślnym formacie{Ana 31 [admin]}
%+vstruktury z nazwami pól{Name:Ana Age:31 Tags:[admin]}
%#vwartość w składni Gomain.User{Name:"Ana", Age:31, Tags:[]string{"admin"}}
%Ttypmain.User
%%dosłowny znak procentu%

%+v to czasownik, po który warto sięgać przy debugowaniu. Wskaźnik na strukturę wypisuje się jako &{...}, a nie jako adres. Mapy wypisują się z posortowanymi kluczami, więc wynik jest stabilny, choć kolejność iteracji po mapie jest losowa.

Liczby całkowite

CzasownikZnaczeniefmt.Sprintf(verb, 255)
%ddziesiętnie255
%bbinarnie11111111
%oósemkowo377
%Oósemkowo z prefiksem 0o0o377
%x / %Xszesnastkowo, małe lub wielkie literyff / FF
%#xszesnastkowo z prefiksem 0x0xff
%cznak o tym punkcie kodowymÿ
%qliterał znakowy w apostrofach'ÿ'
%Uformat UnicodeU+00FF

Liczby zmiennoprzecinkowe

CzasownikZnaczeniefmt.Sprintf(verb, 1234.5678)
%fdziesiętnie, domyślnie 6 miejsc1234.567800
%.2fdziesiętnie, 2 miejsca1234.57
%enotacja naukowa1.234568e+03
%g%e lub %f, co krótsze, bez końcowych zer1234.5678
%vto samo co %g1234.5678

%.2f zaokrągla dokładną binarną wartość liczby, więc fmt.Sprintf("%.2f", 2.675) daje 2.67: najbliższy float64 dla 2.675 jest odrobinę mniejszy. Nigdy nie formatuj kwot pieniężnych z floata; trzymaj grosze w liczbie całkowitej.

Stringi i bajty

CzasownikZnaczeniefmt.Sprintf(verb, "go\n")
%szwykły stringgo i znak nowej linii
%qw cudzysłowach, z widocznymi sekwencjami ucieczki"go\n"
%xszesnastkowo każdy bajt676f0a
% xszesnastkowo ze spacjami67 6f 0a

%s na []byte wypisuje go jako tekst; %v wypisuje liczby ([104 105]).

Inne typy

CzasownikTypWypisuje
%tbooltrue lub false
%pwskaźnik, slice, mapa, kanał, funkcjaadres, na przykład 0xc000012345
%werror (tylko w Errorf)komunikat błędu, a do tego go opakowuje

Szerokość, precyzja i dopełnianie

Między % a czasownikiem możesz wstawić flagi, szerokość i precyzję:

FormaEfekt
%5dszerokość 5, wyrównanie do prawej (dopełnienie spacjami z lewej)
%-5dszerokość 5, wyrównanie do lewej
%05ddopełnienie zerami
%.2f2 cyfry po kropce dziesiętnej
%8.2fszerokość 8 i 2 miejsca po przecinku
%.3snajwyżej 3 znaki stringa
%+dzawsze pokazuj znak
%*dszerokość brana z następnego argumentu

Uwaga: %.0f dla 2.5 wypisuje 2: Go zaokrągla tu połówki do parzystej. Dla stringów szerokość liczy runy, a nie kolumny na ekranie, więc znaki CJK i emoji mogą nadal rozjechać tabelę. Do wyrównanych kolumn ze zmiennym tekstem użyj text/tabwriter, który zmierzy wszystko za ciebie.

Indeksy argumentów

%[n] wybiera argument według pozycji, co pozwala użyć go ponownie:

fmt.Printf("%[2]s %[1]s\n", "world", "hello") // hello world
fmt.Printf("%d %[1]x %[1]b\n", 10)             // 10 a 1010

Errorf i %w

fmt.Errorf buduje error ze stringa formatującego. Z %w dodatkowo opakowuje inny błąd, więc wywołujący nadal mogą wykryć oryginał:

Używaj %w, gdy wywołujący mogą potrzebować sprawdzić przyczynę, a %v, gdy celowo ją ukrywasz. Od Go 1.20 jedno wywołanie Errorf może zawierać kilka czasowników %w. Opakowywanie szczegółowo omawia strona o obsłudze błędów.

Własne formatowanie przez String()

Każdy typ z metodą String() string decyduje, jak pokazują go %v, %s i Println:

%d omija String() i wypisuje liczbę bazową. Dla typów błędów odpowiednikiem jest metoda Error() string, która ma pierwszeństwo przed String().

Gdy czasownik jest zły

fmt nigdy nie wywołuje panic przy złym formacie. Wypisuje problem w miejscu:

fmt.Printf("%d\n", "oops")
fmt.Printf("%d %d\n", 1)
fmt.Printf("%d\n", 1, 2)
%!d(string=oops)
1 %!d(MISSING)
1
%!(EXTRA int=2)

Taki wynik często trafia na produkcję, bo niczego nie wywraca. go vet wyłapuje wszystkie trzy przypadki podczas budowania:

./main.go:8:2: fmt.Printf format %d has arg "oops" of wrong type string
./main.go:9:2: fmt.Printf format %d reads arg #2, but call has 1 arg
./main.go:10:2: fmt.Printf call needs 1 arg but has 2 args

Uwagi o wydajności

fmt przyjmuje każdy argument jako any i sprawdza jego typ w czasie działania (dla struktur, slice'ów i map korzystając z refleksji), co jest w porządku przy logowaniu i wypisywaniu, ale mierzalne w ciasnych pętlach. Do konwersji pojedynczej liczby strconv.Itoa i strconv.FormatFloat są szybsze niż Sprintf. Do budowania długiego stringa w pętli zapisuj do strings.Builder przez fmt.Fprintf(&b, ...) zamiast łączyć wyniki Sprintf.

Najczęściej zadawane pytania

Czym różnią się Println, Printf i Sprintf w Go?

fmt.Println wypisuje argumenty rozdzielone spacjami, ze znakiem nowej linii na końcu. fmt.Printf wypisuje według stringa formatującego i nie dodaje nowej linii. fmt.Sprintf formatuje tak samo jak Printf, ale zamiast wypisywać, zwraca wynik jako string. fmt.Errorf robi to samo i zwraca error.

Jak wypisać strukturę z nazwami pól w Go?

Użyj %+v: fmt.Printf("%+v\n", user) wypisuje {Name:Ana Age:31}. %v wypisuje tylko wartości, {Ana 31}, a %#v wypisuje składnię Go razem z typem, main.User{Name:"Ana", Age:31}.

Jak sformatować liczbę zmiennoprzecinkową do 2 miejsc po przecinku w Go?

Użyj %.2f: fmt.Sprintf("%.2f", 3.14159) zwraca "3.14". Dodaj szerokość, żeby wyrównać kolumny, %8.2f, albo minus, żeby wyrównać do lewej, %-8.2f. strconv.FormatFloat(f, 'f', 2, 64) daje ten sam wynik bez stringa formatującego.

Co robi %w w fmt.Errorf?

%w formatuje błąd jak %v, a do tego go opakowuje, więc nowy błąd niesie oryginał. errors.Is i errors.As mogą wtedy znaleźć opakowany błąd: err := fmt.Errorf("load config: %w", os.ErrNotExist) sprawia, że errors.Is(err, os.ErrNotExist) zwraca true. %w działa tylko w fmt.Errorf.

Dlaczego w wyniku widzę %!d(string=...)?

Czasownik nie pasuje do typu argumentu, na przykład %d dostał string. fmt wypisuje problem w miejscu zamiast wywoływać panic: %!d(string=oops). Brakujące argumenty wypisują %!d(MISSING), a nadmiarowe %!(EXTRA int=2). go vet wyłapuje wszystkie trzy przypadki, zanim uruchomisz program.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ