Das Paket fmt hat drei Familien von Ausgabefunktionen, und jede Familie hat dieselben drei Varianten:
| Funktion | Ausgabe geht an | Format |
|---|---|---|
Print, Println, Printf | Standardausgabe | Standard, Standard mit Leerzeichen und Zeilenumbruch, Format-String |
Sprint, Sprintln, Sprintf | einen zurückgegebenen string | dieselben drei Stile |
Fprint, Fprintln, Fprintf | jeden io.Writer (Datei, Puffer, HTTP-Response) | dieselben drei Stile |
Errorf | einen zurückgegebenen error | Format-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
| Verb | Gibt aus | Beispielausgabe |
|---|---|---|
%v | den Wert im Standardformat | {Ana 31 [admin]} |
%+v | Structs mit Feldnamen | {Name:Ana Age:31 Tags:[admin]} |
%#v | Go-Syntax für den Wert | main.User{Name:"Ana", Age:31, Tags:[]string{"admin"}} |
%T | den Typ | main.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
| Verb | Bedeutung | fmt.Sprintf(verb, 255) |
|---|---|---|
%d | dezimal | 255 |
%b | binär | 11111111 |
%o | oktal | 377 |
%O | oktal mit Präfix 0o | 0o377 |
%x / %X | hexadezimal, klein oder groß | ff / FF |
%#x | hexadezimal mit Präfix 0x | 0xff |
%c | das Zeichen mit diesem Codepoint | ÿ |
%q | ein Zeichenliteral in Anführungszeichen | 'ÿ' |
%U | Unicode-Format | U+00FF |
Floats
| Verb | Bedeutung | fmt.Sprintf(verb, 1234.5678) |
|---|---|---|
%f | dezimal, standardmäßig 6 Stellen | 1234.567800 |
%.2f | dezimal, 2 Stellen | 1234.57 |
%e | wissenschaftliche Notation | 1.234568e+03 |
%g | %e oder %f, was kürzer ist, ohne Nullen am Ende | 1234.5678 |
%v | wie %g | 1234.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
| Verb | Bedeutung | fmt.Sprintf(verb, "go\n") |
|---|---|---|
%s | der reine String | go und ein Zeilenumbruch |
%q | in doppelten Anführungszeichen, Escapes sichtbar | "go\n" |
%x | Hex jedes Bytes | 676f0a |
% x | Hex mit Leerzeichen | 67 6f 0a |
%s auf einem []byte gibt es als Text aus; %v gibt die Zahlen aus ([104 105]).
Andere Typen
| Verb | Typ | Gibt aus |
|---|---|---|
%t | bool | true oder false |
%p | Pointer, Slice, Map, Channel, func | die Adresse, etwa 0xc000012345 |
%w | error (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:
| Form | Wirkung |
|---|---|
%5d | Breite 5, rechtsbündig (links mit Leerzeichen aufgefüllt) |
%-5d | Breite 5, linksbündig |
%05d | mit Nullen auffüllen |
%.2f | 2 Stellen nach dem Dezimalpunkt |
%8.2f | Breite 8 und 2 Nachkommastellen |
%.3s | höchstens 3 Zeichen des Strings |
%+d | Vorzeichen immer anzeigen |
%*d | Breite 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.