In a Go fmt verb such as %8.2f, what do the width and the precision each control?
answer
- two numbers around one dot
- the first one only ever pads
- the second one changes meaning per verb
- strings are the ones that get cut
- a star reads it from an argument
basics
~10 sWidth is the minimum output size, padded with spaces, so %8.2f never prints fewer than 8 characters. Precision follows the dot and is verb-dependent: decimal places for %f, a truncation limit for %s.
solid answer
~40 sIn `%[flags][width].[precision][verb]`, width is the minimum number of runes written — fmt pads with spaces on the left to reach it, and never truncates to it. Precision means different things per verb: for `%f` and `%e` it is the number of digits after the point, for `%g` the number of significant digits, for `%s` and `%q` it is a limit on how much of the *input* is used, so `%.3s` of `"gopher"` gives `gop`, and for integers it sets a minimum digit count padded with leading zeros. Flags modify padding: `-` left-justifies, `0` pads numbers with zeros instead of spaces, `+` always shows a sign. Either number can be `*`, which takes the value from the next operand, so `fmt.Printf("%*d", 5, 42)` pads to width 5 at runtime.
code
go · 5 linesfmt.Printf("|%8.2f|\n", 3.14159) // | 3.14|
fmt.Printf("|%-8s|\n", "go") // |go |
fmt.Printf("|%.3s|\n", "gopher") // |gop|
fmt.Printf("|%06.2f|\n", 3.1415) // |003.14|
fmt.Printf("|%*d|\n", 5, 42) // | 42|go deeper
Know the %[width].[precision]verb shape and be able to print a float to two decimal places with %.2f and pad a column with %-10s.
Explain that width is a minimum measured in runes while precision's meaning is verb-dependent — decimals for %f, significant digits for %g, input truncation for %s, minimum digits for %d.
Demonstrate control over operator-facing output: capping untrusted fields with a precision, quoting them with %q so newlines cannot forge log lines, and computing widths with * rather than by string concatenation.
Decide the house format for machine-read output — fixed columns versus structured records — and keep go vet's printf analyzer in the build so format-argument drift is caught before it reaches a dashboard.
## Anatomy of a verb A fmt verb has the shape ``` %[flags][width][.precision]verb ``` and every part except the verb letter is optional. Written out, `%-08.3f` means: left-justify, zero-pad, minimum width 8, three digits after the point, floating-point decimal. (In practice `-` and `0` together are contradictory and `-` wins.) ## Width Width is a **minimum**. fmt pads the formatted form with spaces until it reaches that size, and if the value is already wider, nothing is cut. This is the single most common misunderstanding: `%3s` applied to `"gopher"` prints `gopher`, not `gop`. Width is what lines up columns in a terminal inspector; it is never a length limit. For most values width is counted in **runes**, not bytes, so a column of names containing non-ASCII text still lines up under `%-12s` — as long as each rune renders one cell wide, which is not guaranteed for East Asian characters or combining marks. Padding is on the left by default. The `-` flag pads on the right instead (left-justification), and the `0` flag pads numeric verbs with leading zeros, placed after any sign: `%+06.2f` of `3.1` yields `+03.10`. ## Precision Precision is everything after the dot, and unlike width its meaning is decided by the verb: - **`%f`, `%e`, `%E`** — the number of digits after the decimal point. `%.2f` of `3.14159` gives `3.14` (rounded, not truncated). The default is 6. - **`%g`, `%G`** — the maximum number of *significant* digits. The special value `-1`, available through `strconv`, means "the shortest representation that round-trips", which is also what `%v` uses for floats. - **`%s`, `%q`, `%v` on strings and byte slices** — a limit on the input consumed, i.e. truncation. `%.3s` of `"gopher"` is `gop`. This is the only place precision shortens output rather than shaping numbers, and it is genuinely useful for capping a user-supplied field in a log line. - **Integers (`%d`, `%x`, ...)** — a minimum number of digits, padded with leading zeros. `%.5d` of `42` gives `00042`. A dot with no number means precision zero: `%.f` of `3.7` gives `4`. ## Combining the two `%8.2f` on `3.14159` produces ` 3.14` — precision first shortens the number to four characters, then width pads it out to eight. Reading it in that order makes the combination easy to predict. `%-10.4s` on a long string truncates to four runes and then pads to ten on the right. ## Taking width or precision from a variable Either number may be written as `*`, which consumes an `int` operand ahead of the value: ```go w := 5 fmt.Printf("%*d\n", w, 42) // " 42" fmt.Printf("%.*f\n", 3, 2.5) // "2.500" ``` This is how you build a table whose column width is computed from the data at runtime, instead of assembling a format string by concatenation. ## %q, and why it belongs in this discussion `%q` prints a double-quoted Go string literal with escapes applied: a value containing a newline prints as `"a\nb"` on one line rather than breaking your log format, and a trailing space becomes visible because the closing quote is right after it. For anything user-supplied — a header value, a filename, a parsed token — `%q` is the safer verb, because `%s` of an empty string is indistinguishable from a missing field and `%s` of hostile text can inject line breaks into a log stream. Precision applies to `%q` the same way as to `%s`, capping the input consumed. ## Getting it wrong fmt reports format errors in the output stream rather than failing: an inapplicable verb gives `%!d(string=hi)`, a missing operand `%!d(MISSING)`, a stray operand `%!(EXTRA int=3)`, and a bad width or precision indicator `%!(BADWIDTH)` or `%!(BADPREC)`. Since `go vet` includes a printf analyzer that checks format strings against arguments in Printf-style calls, most of these are caught before the program ever runs — which is why keeping vet in the build is worth more than memorising the markers.
- How do you set a column width computed at runtime rather than hard-coding it?Use `*` in place of the number and pass the width as an `int` operand before the value: `fmt.Printf("%*d", w, 42)`. Precision works the same way with `%.*f`. This avoids building format strings by concatenation, which defeats the `go vet` printf checks.
- Does width ever truncate a value that is too long?No. Width is a minimum — `%3s` of `"gopher"` still prints all six characters. Only precision truncates, and only for strings and byte slices: `%.3s` gives `gop`. Confusing the two is why terminal tables built with width alone still break their columns on long values.
- Why prefer %q over %s for user-supplied text in a log line?`%q` emits a double-quoted Go literal with escapes, so an embedded newline prints as `\n` instead of splitting your log record, trailing whitespace becomes visible, and an empty value shows as `""` rather than as nothing. It makes hostile or surprising input obvious instead of silently malformed.
saying these in an interview costs you the question
- Says width truncates values that are too long
- Thinks precision means decimal places for every verb
- Believes %.3s rounds instead of cutting the string
- Builds format strings by concatenation instead of using *
- Assumes a bad verb makes Printf return an error