Explain type assertions vs. type switches.
Quick Answer
A type assertion, v, ok := x.(T), checks whether an interface value x holds a concrete type T (or satisfies interface T), returning the value and a boolean success flag in the safe two-value form, or just the value (and a panic on failure) in the single-value form v := x.(T). A type switch, switch v := x.(type) { case int: ...; case string: ... }, checks against multiple possible types in one construct, which is the idiomatic choice whenever you need to branch on more than one possible concrete type. Always prefer the two-value assertion form (v, ok := ...) over the panicking single-value form unless you're certain of the type, since an unexpected type reaching a single-value assertion crashes the program.
Detailed Answer
Both let you recover a concrete type from an interface value, but they fit different shapes of problem.
Single type assertion
var i interface{} = "hello"
s, ok := i.(string)
fmt.Println(s, ok) // "hello", true
n, ok := i.(int)
fmt.Println(n, ok) // 0, false — no panic, since we used the two-value form
s := i.(string) // "hello" — fine here
n := i.(int) // panic: interface conversion: interface {} is string, not int
The single-value form is only safe when you're certain of the underlying type. Otherwise, always use the two-value form.
Type switch for multiple possibilities
func describe(i interface{}) string {
switch v := i.(type) {
case int:
return fmt.Sprintf("int: %d", v)
case string:
return fmt.Sprintf("string: %q", v)
case bool:
return fmt.Sprintf("bool: %t", v)
case nil:
return "nil value"
default:
return fmt.Sprintf("unknown type: %T", v)
}
}
Inside each case, v is automatically narrowed to that specific type, so v.something type-checks against the concrete type in that branch, not the original interface type.
When to use which
Use a single type assertion when you expect exactly one specific type and want to confirm it. Use a type switch when a value could reasonably be one of several types, and you need different behavior per type. A generic describe or render function over a small, known set of inputs is a typical case.