Printing & Formatting with fmt
Almost every Go program prints something: a result, a report, a log line or an error. The standard fmt package does all of it. Its Printf family uses small codes called verbs, such as %d and %s, to control exactly how each value appears.
In this lesson you will learn the verbs you need every day, how to line up columns, how Go prints structs, slices and maps, and how to read simple input from the keyboard.
The printing functions
| Function | Output goes to | Newline added? |
|---|---|---|
fmt.Print(a, b) | Screen (standard output) | No |
fmt.Println(a, b) | Screen | Yes, and spaces between values |
fmt.Printf(format, a, b) | Screen | No, add \n yourself |
fmt.Sprintf(format, a, b) | Returned as a string | No |
fmt.Fprintf(w, format, a) | Any writer, such as a file or os.Stderr | No |
The S versions build a string instead of printing, and the F versions write to a destination you choose. All of them understand the same verbs.
The everyday verbs
A verb starts with % and is replaced by the next argument:
package main
import "fmt"
func main() {
name := "Priya"
age := 20
cgpa := 8.756
fmt.Printf("%s is %d years old\n", name, age)
fmt.Printf("CGPA: %.2f\n", cgpa)
fmt.Printf("CGPA: %v\n", cgpa)
fmt.Printf("%q has type %T\n", name, name)
fmt.Printf("%t %c %U\n", age > 18, 'G', 'G')
fmt.Printf("%d%% complete\n", 75)
}Priya is 20 years old CGPA: 8.76 CGPA: 8.756 "Priya" has type string true G U+0047 75% complete
| Verb | Meaning |
|---|---|
%v | The value in its default format (works for anything) |
%d | Integer in decimal |
%f, %.2f | Float, with 2 digits after the point (rounded) |
%s | String |
%q | Quoted string or character, with Go escapes |
%T | The type of the value |
%t | true or false |
%c, %U | The character for a rune, and its Unicode number |
%% | A literal percent sign |
When in doubt, use %v. For floats, %v prints the shortest form that represents the value exactly, so 8.756 stays 8.756.
Width, padding and number bases
A number between % and the verb sets a minimum width. A - aligns left, and a 0 pads numbers with zeros. You can also print numbers in binary, octal and hexadecimal:
package main
import "fmt"
func main() {
n := 255
fmt.Printf("%d %b %o %x %X\n", n, n, n, n, n)
fmt.Printf("[%5d] [%-5d] [%05d]\n", 42, 42, 42)
fmt.Printf("[%8.2f] [%-8.2f] [%e]\n", 3.14159, 3.14159, 123456.789)
}255 11111111 377 ff FF [ 42] [42 ] [00042] [ 3.14] [3.14 ] [1.234568e+05]
Widths make neat tables. Here is a bill from a stationery shop, with the item name left-aligned in 14 characters and the price right-aligned in 8:
package main
import "fmt"
func main() {
items := []string{"Notebook", "Gel pen", "Geometry box"}
prices := []float64{45, 10, 120.5}
total := 0.0
for i, item := range items {
fmt.Printf("%-14s ₹%8.2f\n", item, prices[i])
total += prices[i]
}
fmt.Printf("%-14s ₹%8.2f\n", "Total", total)
}Notebook ₹ 45.00 Gel pen ₹ 10.00 Geometry box ₹ 120.50 Total ₹ 175.50
For strings, Go counts the width in characters (runes), not bytes, so Hindi or Tamil names line up correctly too, as long as the font gives every character the same width.
Printing structs, slices and maps
%v knows how to print every type. Two variants add detail: %+v adds struct field names, and %#v prints the value as Go source code, which is great for debugging.
package main
import "fmt"
type Student struct {
Name string
Marks int
}
func main() {
s := Student{"Kabir", 88}
fmt.Printf("%v\n", s)
fmt.Printf("%+v\n", s)
fmt.Printf("%#v\n", s)
fmt.Println(&s)
cities := []string{"Pune", "Kochi"}
fmt.Printf("%v %q\n", cities, cities)
stock := map[string]int{"pens": 40, "erasers": 15}
fmt.Println(stock)
var empty []int
var err error
fmt.Println(empty, len(empty), err)
}{Kabir 88}
{Name:Kabir Marks:88}
main.Student{Name:"Kabir", Marks:88}
&{Kabir 88}
[Pune Kochi] ["Pune" "Kochi"]
map[erasers:15 pens:40]
[] 0 <nil>A pointer to a struct prints with a leading &. When printing a map, fmt sorts the keys, so the output is always the same. (Looping over a map with for range is not sorted; see Maps.) A nil error or pointer prints as <nil>. You will learn how a type can choose its own %v text with a String() method in Interfaces.
Building strings and spotting mistakes
Sprintf is the easy way to build a formatted string, such as an invoice number:
package main
import (
"fmt"
"os"
)
func main() {
invoice := fmt.Sprintf("INV-%04d", 37)
fmt.Println(invoice)
fmt.Fprintln(os.Stderr, "warning: printer offline")
fmt.Printf("%d items\n", "five")
fmt.Printf("%s and %s\n", "chai")
}INV-0037 warning: printer offline %!d(string=five) items chai and %!s(MISSING)
Fprintln(os.Stderr, ...) writes to standard error, the stream for warnings and errors, which the terminal shows alongside normal output. The last two lines show how fmt reports bad verbs instead of crashing: %!d(string=five) means "the %d verb got a string", and %!s(MISSING) means an argument is missing. go vet finds these mistakes before you run the program.
Reading input with fmt.Scan
fmt.Scan reads space-separated values from the keyboard into variables. You pass the address of each variable with & (explained in Pointers) so Scan can fill it:
package main
import "fmt"
func main() {
var name string
var age int
fmt.Print("Enter name and age: ")
if _, err := fmt.Scan(&name, &age); err != nil {
fmt.Println("Could not read input:", err)
return
}
fmt.Printf("Hello %s, next year you will be %d\n", name, age+1)
}Enter name and age: Farhan 23 Hello Farhan, next year you will be 24
Scan returns how many values it read and an error, for example when the user types letters where a number is expected. For whole lines that may contain spaces, use bufio.Scanner, covered in Standard Library: os, io & time.
Common mistakes
- Forgetting
\ninPrintf. The next output continues on the same line. - Using
%dfor a float or%ffor an int. You get%!d(float64=...)text. Use%vif unsure. - Passing the variable instead of its address to
Scan.fmt.Scan(name)cannot fillname; writefmt.Scan(&name). - Printing a map with
for rangeand expecting a fixed order. Onlyfmt's whole-map printing is sorted.
Key points
Printlnis quick;Printfgives full control with verbs;Sprintfreturns a string.%vprints any value;%+vadds field names;%#vshows Go syntax;%Tshows the type.- Width and precision such as
%-14sand%8.2fline up tables. fmtprints maps with sorted keys and nil values as<nil>.- Wrong verbs appear as
%!verb(...)in the output;go vetcatches them early.
Exercise
Print a marksheet for Ananya with three subjects: Maths 91, Physics 78 and Chemistry 84. Each line should show the subject left-aligned in 12 characters and the marks right-aligned in 4. Finish with the percentage to one decimal place, followed by a % sign, and create a roll number string ROLL-0042 with Sprintf.
Show solution
package main
import "fmt"
func main() {
subjects := []string{"Maths", "Physics", "Chemistry"}
marks := []int{91, 78, 84}
roll := fmt.Sprintf("ROLL-%04d", 42)
fmt.Println("Ananya", roll)
total := 0
for i, sub := range subjects {
fmt.Printf("%-12s%4d\n", sub, marks[i])
total += marks[i]
}
percent := float64(total) / 3
fmt.Printf("Percentage: %.1f%%\n", percent)
}Ananya ROLL-0042 Maths 91 Physics 78 Chemistry 84 Percentage: 84.3%
The total is 253 and 253 divided by 3 is 84.33..., which %.1f rounds to 84.3. %% prints the percent sign.
Quick Quiz
1. Which verb adds field names when printing a struct?
%+v prints structs as {Name:Kabir Marks:88} with the field names.
2. What does fmt.Sprintf("%05d", 42) return?
The 0 flag pads with zeros to a width of 5.
3. In what order does fmt.Println print the keys of a map?
fmt sorts map keys when printing a whole map, so output is consistent.
4. What does %T print for the value 3.5?
%T prints the Go type, and untyped float constants default to float64.
Learn Go with a mentor
Free lessons get you started. Our Programming & Software Development training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
