Skip to content

Day 032 — fmt Verbs Deep Dive

Month 2 · Week 1 · ⬅ Day 031 · Day 033 ➡ · Journal index

🎯 Learning Objective

Master the fmt verbs — the %v/%+v/%#v/%T family, integer/float/string formatting with width/precision/flags — and the Stringer/Formatter hooks plus %w error wrapping.

📚 Topics

  • %v, %+v, %#v, %T and when each differs
  • Numeric verbs: %d %b %o %x %X %c %U, floats %f %e %g
  • Width, precision, flags (+, -, 0, space, #)
  • fmt.Stringer, argument indexing %[1]d, %w

📖 Reading / Sources

📝 Notes

  • %v is the default format; %+v adds struct field names; %#v prints Go-syntax (re-pasteable) form; %T prints the dynamic type → [[fmt-v-family]].
  • Implement fmt.Stringer (String() string) and %v/%s use it automatically. %#v deliberately ignores String() to show the raw value — handy for debugging what something really is.
  • Integers: %d decimal, %b binary, %o octal, %x/%X hex (lower/upper), %c the rune for a code point, %U the U+XXXX form. %q quotes strings and runes.
  • Floats: %f fixed, %e scientific, %g the compact "use whichever is shorter" form (best default for unknown magnitudes).
  • Width & precision: %8.3f = min width 8, 3 decimals. Flags: - left-justify, 0 zero-pad, + always show sign, space leaves room for a sign, # alternate form (0x prefix, etc.). On %x of a string, the space flag (% x) separates bytes.
  • Argument indexing %[1]d reuses the nth argument — great for printing one value in several bases without repeating it.
  • A verb/type mismatch doesn't panic: fmt.Printf("%d", "hi") prints %!d(string=hi). Spotting %! in output is a fast bug signal → [[fmt-bad-verb]].
  • Print vs Println vs Printf: Println adds spaces between operands and a newline; Print adds spaces only between non-string operands; Printf is fully explicit.
  • The Sprint* family returns a string; the Fprint* family writes to any io.Writer (so fmt.Fprintln(os.Stderr, …) and fmt.Fprintf(&builder, …) reuse the same engine).
  • fmt.Errorf("...: %w", err) wraps an error so errors.Is/errors.As can unwrap it — the single most important fmt idiom for error handling → [[error-wrapping]].

💻 Code Examples

type point struct{ X, Y int }
func (p point) String() string { return fmt.Sprintf("(%d,%d)", p.X, p.Y) }

p := point{3, 4}
fmt.Printf("%v\n", p)   // (3,4)      — uses Stringer
fmt.Printf("%#v\n", p)  // main.point{X:3, Y:4} — ignores Stringer
fmt.Printf("%T\n", p)   // main.point — dynamic type
fmt.Printf("%[1]d in dec, %[1]x in hex\n", 250) // reuse arg 1

Full code: examples/month-02/fmt-verbs/main.go · Run: go run ./examples/month-02/fmt-verbs

🏋️ Exercises / Practice

Exercise Status Link
Inspect format output (%v/%+v/%#v/%T) in the example examples/month-02/fmt-verbs

🐛 Mistakes Made

  • Printed a struct with %v and got {3 4} with no field names — switched to %+v for debugging.
  • Used %d on a float64 and saw %!d(float64=3.14); the %! marker told me the verb was wrong.

❓ Open Questions

  • When is implementing fmt.Formatter (full control) worth it over a simple Stringer?

🧠 Active Recall (answer without looking)

  1. Q: A type has a String() method. Which verb still shows its underlying Go value?

    A `%#v` — it prints the Go-syntax representation and deliberately ignores `Stringer`. (`%v`/`%s` would call `String()`.)

  2. Q: What does fmt.Printf("%d", "oops") produce, and why no panic?

    A `%!d(string=oops)`. `fmt` reports verb/argument mismatches inline with a `%!` marker instead of panicking, so formatting bugs are visible but non-fatal.

🪶 Feynman Reflection

fmt verbs are a tiny language for describing how a value should look. %v says "just show me"; %+v says "and label the fields"; %#v says "show me the actual Go code"; %T says "what is this thing?". Width/precision/flags are the fine-print knobs, and %w is the special one that threads an error through so it can be unwrapped later.

🕳️ Knowledge Gaps

  • fmt.Formatter/fmt.GoStringer custom verbs; locale-free number formatting.

✅ Summary

I can format any value precisely, hook into output with Stringer, read the %! mismatch markers, and wrap errors with %w.

⏭️ Next Steps / Prep for Tomorrow

  • Day 033: strings, strconv, and bytes — the text-wrangling workhorses.

Time spent Difficulty Confidence
90 min 🟦⬜⬜⬜⬜ 🟦🟦🟦🟦⬜

Suggested commit: feat(examples): fmt verbs and Stringer deep dive (day 032)