Menu

Golang Printf und Sprintf: Spickzettel der fmt-Format-Verben

Wie das Paket fmt von Go Werte ausgibt und formatiert: Println vs Printf vs Sprintf vs Errorf, die vollständige Tabelle der Format-Verben (%v, %+v, %d, %s, %q, %f, %T, %w und mehr), Breite, Genauigkeit und Padding.

Diese Seite enthält ausführbare Editoren - bearbeiten, ausführen und Ausgabe sofort sehen.

Das Paket fmt hat drei Familien von Ausgabefunktionen, und jede Familie hat dieselben drei Varianten:

FunktionAusgabe geht anFormat
Print, Println, PrintfStandardausgabeStandard, Standard mit Leerzeichen und Zeilenumbruch, Format-String
Sprint, Sprintln, Sprintfeinen zurückgegebenen stringdieselben drei Stile
Fprint, Fprintln, Fprintfjeden io.Writer (Datei, Puffer, HTTP-Response)dieselben drei Stile
Errorfeinen zurückgegebenen errorFormat-String, dazu %w zum Wrappen

Println setzt Leerzeichen zwischen die Operanden und einen Zeilenumbruch ans Ende. Printf fügt nichts hinzu: Du schreibst \n selbst. Print setzt Leerzeichen nur zwischen Operanden, die beide keine Strings sind. Das überrascht genug, dass der meiste Code Println oder Printf nutzt.

Format-Verben

Allgemein

VerbGibt ausBeispielausgabe
%vden Wert im Standardformat{Ana 31 [admin]}
%+vStructs mit Feldnamen{Name:Ana Age:31 Tags:[admin]}
%#vGo-Syntax für den Wertmain.User{Name:"Ana", Age:31, Tags:[]string{"admin"}}
%Tden Typmain.User
%%ein wörtliches Prozentzeichen%

%+v ist das Verb der Wahl beim Debuggen. Ein Pointer auf ein Struct erscheint als &{...} statt als Adresse. Maps werden mit sortierten Schlüsseln ausgegeben, die Ausgabe ist also stabil, obwohl die Iterationsreihenfolge von Maps zufällig ist.

Ganzzahlen

VerbBedeutungfmt.Sprintf(verb, 255)
%ddezimal255
%bbinär11111111
%ooktal377
%Ooktal mit Präfix 0o0o377
%x / %Xhexadezimal, klein oder großff / FF
%#xhexadezimal mit Präfix 0x0xff
%cdas Zeichen mit diesem Codepointÿ
%qein Zeichenliteral in Anführungszeichen'ÿ'
%UUnicode-FormatU+00FF

Floats

VerbBedeutungfmt.Sprintf(verb, 1234.5678)
%fdezimal, standardmäßig 6 Stellen1234.567800
%.2fdezimal, 2 Stellen1234.57
%ewissenschaftliche Notation1.234568e+03
%g%e oder %f, was kürzer ist, ohne Nullen am Ende1234.5678
%vwie %g1234.5678

%.2f rundet den exakten Binärwert des Floats, also ist fmt.Sprintf("%.2f", 2.675) gleich 2.67: Der float64, der 2.675 am nächsten liegt, ist etwas kleiner. Formatiere Geld nie aus einem Float; speichere Cent in einer Ganzzahl.

Strings und Bytes

VerbBedeutungfmt.Sprintf(verb, "go\n")
%sder reine Stringgo und ein Zeilenumbruch
%qin doppelten Anführungszeichen, Escapes sichtbar"go\n"
%xHex jedes Bytes676f0a
% xHex mit Leerzeichen67 6f 0a

%s auf einem []byte gibt es als Text aus; %v gibt die Zahlen aus ([104 105]).

Andere Typen

VerbTypGibt aus
%tbooltrue oder false
%pPointer, Slice, Map, Channel, funcdie Adresse, etwa 0xc000012345
%werror (nur in Errorf)die Meldung des Fehlers, und wrappt ihn

Breite, Genauigkeit und Padding

Zwischen % und das Verb kannst du Flags, eine Breite und eine Genauigkeit setzen:

FormWirkung
%5dBreite 5, rechtsbündig (links mit Leerzeichen aufgefüllt)
%-5dBreite 5, linksbündig
%05dmit Nullen auffüllen
%.2f2 Stellen nach dem Dezimalpunkt
%8.2fBreite 8 und 2 Nachkommastellen
%.3shöchstens 3 Zeichen des Strings
%+dVorzeichen immer anzeigen
%*dBreite aus dem nächsten Argument

Beachte: %.0f von 2.5 ergibt 2, denn Go rundet hier auf die gerade Zahl. Bei Strings zählt die Breite Runes, keine Anzeigespalten, also können CJK-Zeichen und Emoji eine Tabelle trotzdem verschieben. Für ausgerichtete Spalten mit variablem Text übernimmt text/tabwriter das Messen für dich.

Argumentindizes

%[n] wählt ein Argument nach Position, damit kannst du eins wiederverwenden:

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

Errorf und %w

fmt.Errorf baut einen error aus einem Format-String. Mit %w wrappt es zusätzlich einen anderen Fehler, sodass Aufrufer das Original noch erkennen können:

Nimm %w, wenn Aufrufer die Ursache prüfen müssen könnten, und %v, wenn du sie bewusst verbirgst. Seit Go 1.20 darf ein Errorf-Aufruf mehrere %w-Verben enthalten. Die Seite zur Fehlerbehandlung erklärt das Wrapping im Detail.

Eigene Formatierung mit String()

Jeder Typ mit einer Methode String() string bestimmt, wie %v, %s und Println ihn anzeigen:

%d umgeht String() und gibt die zugrunde liegende Zahl aus. Bei Fehlertypen ist die entsprechende Methode Error() string, die Vorrang vor String() hat.

Wenn das Verb falsch ist

fmt löst bei einem falschen Format nie eine Panic aus. Es gibt das Problem direkt in der Ausgabe aus:

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)

Solche Ausgaben landen gern in Produktion, weil sie nichts zum Absturz bringen. go vet findet alle drei beim Build:

./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

Hinweise zur Performance

fmt nimmt jedes Argument als any und untersucht seinen Typ zur Laufzeit (bei Structs, Slices und Maps per Reflection). Für Logging und Ausgaben ist das in Ordnung, in engen Schleifen aber messbar. Um eine einzelne Zahl zu konvertieren, sind strconv.Itoa und strconv.FormatFloat schneller als Sprintf. Um in einer Schleife einen langen String zu bauen, schreib mit fmt.Fprintf(&b, ...) in einen strings.Builder, statt Ergebnisse von Sprintf zu verketten.

Häufig gestellte Fragen

Was ist der Unterschied zwischen Println, Printf und Sprintf in Go?

fmt.Println gibt seine Argumente durch Leerzeichen getrennt mit einem Zeilenumbruch am Ende aus. fmt.Printf gibt anhand eines Format-Strings aus und hängt keinen Zeilenumbruch an. fmt.Sprintf formatiert genauso wie Printf, gibt das Ergebnis aber als String zurück, statt es auszugeben. fmt.Errorf macht dasselbe und gibt einen error zurück.

Wie gebe ich in Go ein Struct mit Feldnamen aus?

Mit %+v: fmt.Printf("%+v\n", user) gibt {Name:Ana Age:31} aus. %v gibt nur die Werte aus, {Ana 31}, und %#v gibt Go-Syntax samt Typ aus, main.User{Name:"Ana", Age:31}.

Wie formatiere ich in Go einen Float auf 2 Nachkommastellen?

Mit %.2f: fmt.Sprintf("%.2f", 3.14159) gibt "3.14" zurück. Füg eine Breite hinzu, um Spalten auszurichten, %8.2f, oder ein Minuszeichen für Linksbündigkeit, %-8.2f. strconv.FormatFloat(f, 'f', 2, 64) liefert dasselbe Ergebnis ohne Format-String.

Was macht %w in fmt.Errorf?

%w formatiert einen Fehler wie %v und wrappt ihn zusätzlich, sodass der neue Fehler das Original mitträgt. errors.Is und errors.As finden den gewrappten Fehler dann: err := fmt.Errorf("load config: %w", os.ErrNotExist) macht errors.Is(err, os.ErrNotExist) wahr. %w funktioniert nur in fmt.Errorf.

Warum zeigt meine Ausgabe %!d(string=...)?

Das Verb passt nicht zum Typ des Arguments, zum Beispiel %d mit einem String. fmt gibt das Problem direkt in der Ausgabe aus, statt eine Panic auszulösen: %!d(string=oops). Fehlende Argumente ergeben %!d(MISSING) und überzählige %!(EXTRA int=2). go vet findet alle drei, bevor du das Programm startest.

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S