If a type implements both error and fmt.Stringer, which method does fmt.Printf("%v", x) call?
answer
- fmt asks a fixed list of questions
- one interface outranks all the others
- being an error settles it
- the friendlier method becomes dead code
- Format sees the verb and the flags
basics
~10 sError() wins. For the string-accepting verbs fmt checks error before fmt.Stringer, so the String method is dead code on a type that is also an error. Only fmt.Formatter takes precedence over both.
solid answer
~40 sfmt tries a fixed sequence of interfaces on each operand. `fmt.Formatter` — `Format(f fmt.State, verb rune)` — is checked first and, if present, handles every verb itself, including `%d`. Otherwise, for `%#v` fmt looks for `fmt.GoStringer`; for `%v`, `%s`, `%q`, `%x` and `%X` it looks for `error` and then for `fmt.Stringer`, in that order. Anything else falls through to reflection-based default formatting. So a type with both `Error() string` and `String() string` always prints its `Error()` text, and the `String()` method never runs under fmt — a silent trap when someone adds a friendlier `String()` to an error type and wonders why logs are unchanged. Implementing both on one type is best avoided; if you truly need verb-sensitive output, implement `Formatter` and inspect `f.Flag('+')`, `f.Width()` and `f.Precision()`.
code
go · 7 linestype StatusErr struct{ Code int }
func (e *StatusErr) Error() string { return fmt.Sprintf("status %d", e.Code) }
func (e *StatusErr) String() string { return "service unavailable" }
fmt.Printf("%v\n", &StatusErr{Code: 503}) // status 503go deeper
Remember the outcome rather than the machinery: if a type has Error(), that is the text fmt prints, and adding String() to it changes nothing.
Be able to recite the order fmt tries — Formatter, then GoStringer for %#v, then error, then Stringer — and note that numeric verbs skip all of them.
Show that you would catch the dead String method in review, pin a type's printed form with a test, and know when Formatter with fmt.State's Flag, Width and Precision earns its extra complexity.
Set the rule that a type has exactly one printed form and that operator-facing output is a contract: changing which of these interfaces a shared type implements silently rewrites every log line it appears in.
## The order fmt uses Every operand handed to `fmt.Printf`, `fmt.Sprintf` or `fmt.Fprintf` arrives as an interface value, and fmt asks a series of questions about it before falling back to reflection: 1. **Does it implement `fmt.Formatter`?** If yes, fmt calls `Format(f fmt.State, verb rune)` and hands over completely — for *every* verb, numeric ones included. Nothing after this point is consulted. 2. **Is the verb `%#v`, and does it implement `fmt.GoStringer`?** If yes, `GoString() string` supplies the text. 3. **Is the verb one that accepts a string — `%v`, `%s`, `%q`, `%x`, `%X`?** If yes, fmt checks, in this order: - `error` (`Error() string`), - `fmt.Stringer` (`String() string`). 4. Otherwise, default formatting by reflection: struct braces, slice brackets, sorted map keys, and so on. The consequence people hit in practice is step 3's ordering: **`Error()` beats `String()`**. A type carrying both methods prints its error text everywhere fmt is involved, and the `String()` method is unreachable through fmt. ## Why this bites The typical sequence is that a service defines a status or failure type with `Error() string` so it satisfies `error`. Later someone wants nicer operator-facing output in a terminal inspector and adds a `String() string` returning a human-friendly summary. Nothing changes in the logs. There is no compile error, no vet diagnostic, no runtime marker — the new method simply never runs. The engineer then reaches for explicit calls (`log.Print(x.String())`) and ends up with two spellings of the same value drifting apart. The rule to remember and to enforce in review: **one type, one printed form.** If a type is an error, `Error()` *is* its printed form. If you need a second, richer rendering, put it on a different method with a name that says so (`Detail()`, `Summary()`), call it explicitly, and do not name it `String()`. ## fmt.Formatter, the escape hatch ```go type Formatter interface { Format(f State, verb rune) } ``` `fmt.State` gives the method everything fmt knows about the call site: - `Write([]byte) (int, error)` — State is an `io.Writer`, so you emit output by writing to it (often via `io.WriteString(f, s)`). - `Width() (int, bool)` and `Precision() (int, bool)` — the numbers from the verb, plus whether they were specified at all. - `Flag(c int) bool` — whether a flag such as `'+'`, `'#'`, `'-'`, `' '` or `'0'` was present. That is how a type offers `%v` for a compact form and `%+v` for a detailed one, or gives `%d` a meaning of its own. Because `Format` intercepts *every* verb, it must handle the ones it does not care about — the convention is to emit the standard bad-verb marker, `fmt.Fprintf(f, "%%!%c(...)", verb)`, or to fall back to default formatting of a conversion of the receiver. The cost is real: `Formatter` is more code, is easy to get wrong for unexpected verbs, and — like `String()` — must not format the receiver in a way that re-enters itself. Most types are better served by a plain `String()`. Reach for `Formatter` when the printed form genuinely differs by verb or flag: a big value with a summary and a full form, a unit-carrying number, a redacting wrapper that prints in full only under `%+v`. ## Related precedence questions - `%#v` and `GoStringer` sit *outside* the Stringer branch, so a type may have both a `String()` for readable output and a `GoString()` for a Go-literal form without either shadowing the other. - Numeric verbs never consult `error` or `Stringer` at all. `%d` on an error type with an integer underlying type prints the number. - A `Formatter` on a type that is also an `error` means `Format` handles error printing too — including when the value is printed through the `error` interface elsewhere — so that combination needs care. ## How to verify precedence in practice Write the tiny experiment rather than reasoning about it: a struct with both methods, one `fmt.Printf("%v")`, and read the output. Better still, write it as a test — the printed form of an operator-facing type is worth pinning, because a later refactor that adds or removes one of these interfaces changes every log line the type appears in, without touching a single call site.
- Which interface outranks both error and fmt.Stringer, and what does it receive?`fmt.Formatter`, whose single method is `Format(f fmt.State, verb rune)`. fmt checks it first and then steps aside completely, for every verb including `%d`. `fmt.State` is an `io.Writer` that also exposes `Width()`, `Precision()` and `Flag(c int)`, so the method can render differently for `%v` and `%+v`.
- When is implementing fmt.Formatter worth the extra code?When the printed form genuinely differs by verb or flag — a compact `%v` and a detailed `%+v`, a value that redacts itself unless a flag is set, or a type giving `%d` its own meaning. Otherwise prefer a plain `String()`: Formatter intercepts every verb, so you must handle the ones you did not plan for.
- Does adding a String method to an existing error type change anything at all?Not through fmt, and not through `log` or anything else that formats the value — `Error()` is found first for every string-accepting verb. It only runs if someone calls it explicitly. That silence is the danger: the method looks alive in review and is unreachable in practice.
saying these in an interview costs you the question
- Says String wins because it is more specific
- Thinks fmt calls both methods and joins them
- Expects a compile error for the ambiguous pair
- Believes Formatter only affects %v
- Claims a String method changes what log.Printf writes for an error