Explain type switch semantics. What does this print?
Question 85MediumGo 1.22 to 1.25
func describe(x any) string {
switch v := x.(type) {
case nil:
return "nil"
case int, int64:
return fmt.Sprintf("integer %T", v) // v has type any here
case error:
return "error: " + v.Error()
case fmt.Stringer:
return "stringer: " + v.String()
case *bytes.Buffer:
return "buffer" // never reached for *bytes.Buffer, see below
default:
return fmt.Sprintf("other %T", v)
}
}
var p *bytes.Buffer
fmt.Println(describe(nil)) // nil
fmt.Println(describe(int64(3))) // integer int64
fmt.Println(describe(p)) // stringer: <nil>
fmt.Println(describe(errors.New("x"))) // error: x
The rules:
- Cases are tested in order.
*bytes.Bufferimplementsfmt.Stringer, so the Stringer case matches first and the later concrete case is unreachable for that type. The compiler does not warn you when an interface case comes first; staticcheck's SA4020 (unreachable case clause) does. - In a case that lists one type,
vhas that type. In a case that lists several types, or indefault,vkeeps the original interface type. case nilmatches only a nil interface. A typed nil pointer matches its type case.(*bytes.Buffer).Stringhandles a nil receiver and returns"<nil>".fallthroughis not allowed in a type switch.
More on Interfaces, Methods & Embedding
- Q83How do you decide between value and pointer receivers?
- Q84Compare
v := x.(T)withv, ok := x.(T). What happens whenTis an interface type? - Q86Is struct embedding inheritance? How does method promotion work?
- Q87What does this print? (no virtual dispatch with embedding)
- Q88Embedding
Tvs*T: how does each affect the method set of the outer struct? - Q89What happens when two embedded types provide the same field or method name?