Formatted Printing with fmt
The fmt package prints and formats values. Its Printf family uses verbs such as %d and %s with optional width, precision and flags, much like C's printf — plus Go-specific verbs that print any value, its type, or its Go syntax. This lesson covers the verbs you'll actually use and the functions that write to strings, files and errors.
The fmt functions
| Writes to… | Plain | With newline | Formatted |
|---|---|---|---|
| Standard output | Print | Println | Printf |
| A string (returned) | Sprint | Sprintln | Sprintf |
| Any writer (file, network, stderr) | Fprint | Fprintln | Fprintf |
A []byte (appended) | Append | Appendln | Appendf |
There's also fmt.Errorf, which formats an error message (lesson 44).
package main import ( "fmt" "os" ) func main() { label := fmt.Sprintf("Order #%d", 1042) fmt.Println(label) fmt.Fprintln(os.Stdout, "written to standard output") err := fmt.Errorf("item %q is out of stock", "lamp") fmt.Println(err) }
Order #1042 written to standard output item "lamp" is out of stock
General verbs
%v prints any value in a sensible default format. With + it adds struct field names, and %#v prints the value as Go source code — useful for debugging:
package main import "fmt" type Book struct { Title string Pages int } func main() { b := Book{"Dune", 412} tags := []string{"sci-fi", "classic"} stock := map[string]int{"dune": 3} fmt.Printf("%v\n", b) fmt.Printf("%+v\n", b) fmt.Printf("%#v\n", b) fmt.Printf("%v %#v\n", tags, tags) fmt.Printf("%v\n", stock) fmt.Printf("%T %T %T\n", b, tags, stock) fmt.Printf("100%%\n") }
{Dune 412}
{Title:Dune Pages:412}
main.Book{Title:"Dune", Pages:412}
[sci-fi classic] []string{"sci-fi", "classic"}
map[dune:3]
main.Book []string map[string]int
100%%% prints a literal percent sign. Maps are always printed with their keys sorted, so the output is predictable.
Numbers
package main import "fmt" func main() { n := 255 fmt.Printf("%d %b %o %x %X %#x\n", n, n, n, n, n, n) fmt.Printf("%c %U\n", 9731, 9731) f := 1234.5678 fmt.Printf("%f | %.2f | %.0f\n", f, f, f) fmt.Printf("%e | %g | %g\n", f, f, 0.000001234) }
255 11111111 377 ff FF 0xff ☃ U+2603 1234.567800 | 1234.57 | 1235 1.234568e+03 | 1234.5678 | 1.234e-06
%f defaults to six decimal places; %.2f gives two. %g uses whichever of plain or exponent notation is shorter, and is what %v uses for floats.
Strings and booleans
package main import "fmt" func main() { s := "say \"hi\"\n" fmt.Printf("%s", s) fmt.Printf("%q\n", s) fmt.Printf("%x\n", "Go") fmt.Printf("%t %v\n", true, false) }
say "hi" "say \"hi\"\n" 476f true false
%q prints a quoted, escaped string. It's excellent for debugging, because it makes empty strings, spaces and invisible characters obvious.
Width, precision and flags
Between the % and the verb you can put flags, a minimum width and a precision. Numbers align right and strings align right by default; the - flag aligns left:
package main import "fmt" func main() { items := []struct { name string qty int price float64 }{ {"Notebook", 4, 3.5}, {"Pen", 10, 1.2}, {"Backpack", 1, 39.9}, } fmt.Printf("%-10s %4s %8s\n", "Item", "Qty", "Price") for _, it := range items { fmt.Printf("%-10s %4d %8.2f\n", it.name, it.qty, it.price) } fmt.Printf("[%05d] [%+d] [%x] [% x]\n", 42, 42, "hi", "hi") fmt.Printf("[%*d] [%-*d]\n", 6, 7, 6, 7) // width taken from an argument fmt.Printf("%.3s\n", "Gopher") // precision truncates strings }
Item Qty Price Notebook 4 3.50 Pen 10 1.20 Backpack 1 39.90 [00042] [+42] [6869] [68 69] [ 7] [7 ] Gop
| Flag | Effect |
|---|---|
- | Left-align within the width |
0 | Pad numbers with leading zeros |
+ | Always show the sign; with %v, show struct field names |
# | Alternate format: 0x prefix for hex, Go syntax for %#v |
| space | Leave a space for a missing plus sign; put spaces between bytes with % x |
Argument indexes
%[n] picks the n-th argument, so you can reuse one:
package main import "fmt" func main() { fmt.Printf("%[1]d in hex is %[1]x and in binary is %[1]b\n", 10) }
10 in hex is a and in binary is 1010
Mistakes fmt reports
A wrong verb or a missing argument doesn't crash; fmt prints a marker such as %!d(string=…) into the output instead. Better still, go vet finds these mistakes before you run the program:
package main import "fmt" func main() { name, age := "Ana", 34 fmt.Printf("%d is %s years old\n", name, age) fmt.Printf("%s has %d items\n", name) }
main.go:7:14: fmt.Printf format %d has arg name of wrong type string main.go:8:21: fmt.Printf format %d reads arg #2, but call has 1 arg
Try it yourself
Print a receipt with aligned columns and a total line. Try changing the widths.
Coffee 2.80 Croissant 3.25 Orange juice 4.10 TOTAL 10.15