a common mistake when using Fmt Sprintf
Fast recall
Quick revision
Core answer
Practical understanding of Fmt Sprintf.
Repeating a definition without saying when to use it.
Give one trade-off and say how you would test it.
Interview-ready guide
Interview answer
Both turn an int into a string; the difference is generality vs cost:
n := 42
strconv.Itoa(n) // "42" — direct, fast
fmt.Sprintf("%d", n) // "42" — parses format, reflects, formatsSprintf's machinery: parse the format string at runtime, reflect over the argument's type, dispatch the verb, allocate the result. It's a full mini-interpreter per call. Itoa is a tight decimal-encoding routine — no format, no reflection, one small allocation.
The performance folklore is real: benchmarks consistently show Sprintf ~3-5x Itoa for the simple int case, more with multiple args. In a hot path (per-request logging, tight loops, serialization), that compounds.
When each is right: Itoa (and the strconv family — FormatInt, FormatFloat, Atoi) when the conversion is EXACTLY one value → one string with no surrounding text. Sprintf when you're composing — text + values + formatting (widths, precision, multiple args) — the moment there's a sentence to build, the format language earns its cost.
The hybrid most real code uses: build the static parts with concatenation or Builder, use strconv for the value insertions — the pattern every fast logger uses internally.
a common mistake when using Fmt Sprintf
Direct Answer
Itoa: int→string only, no format parsing — fast. Sprintf: full format language, any types — 3-5x slower. Hot paths: Itoa. Formatted output: Sprintf.
Deep Dive & Architecture
Why the cost gap is structural, not incidental: Sprintf's runtime format parsing means — per call — a scan of the format string, a type-switch on each argument (via reflection for interface-boxed args), verb dispatch, and a fresh allocation for the output. Itoa's path: one if-chain for the sign, a loop of divide-by-10 digit extraction, one allocation. The reflection and parsing are Sprintf's whole value (any type, any format) and its whole overhead — the same generality/cost trade the entire fmt package makes (Print vs manual strconv: identical story).
The Append family as the zero-allocation tier: strconv.AppendInt(buf, n, 10) writes into a caller-provided []byte — no string allocation at all. encoding/json's int encoder is literally this call — the hot path inside the standard library skips fmt entirely. For your own hot paths, the progression is: Sprintf (readable) → Itoa/FormatInt (one value) → AppendInt into a reused buffer (zero alloc, maximal ceremony).
The API-design note interviewers reward: Go's own hot-path code (encoding/json, strconv-based loggers) never uses fmt for inner loops — fmt is the presentation layer (user-facing strings, errors, top-level logs), and the ecosystem's performance discipline is 'fmt at the edges, strconv/append in the cores.' Matching that split in your own code is the sign of knowing both tools.
Common Mistakes & Pitfalls
Repeating a definition without saying when to use it.
Check your understanding
Answer these without looking back at the article.
- What is Fmt Sprintf, and when would you use it?
- When would you use Fmt Sprintf in a real project?
- How would you compare Fmt Sprintf with an alternative?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.