Expression switches
…
If the switch expression evaluates to an untyped constant, it is first implicitly converted to its default type. The predeclared untyped value
nil
cannot be used as a switch expression. The switch expression type must be comparable.
In this paragraph, “switch expression” refers to the expression that optionally comes after the switch
keyword, as in:
switch len(x) {
So first off, if it’s a untyped constant, it’s first converted to its default type. This matters for the comparison to the case expressions. Of course, using constants, typed or untyped, in an switch
statement will be somewhat rare, but it is permitted, and can be useful in some cases. But note the exception: Untyped nil
cannot be used here (though it can be used as a case expression).
Next, the switch expression must be comparable. So let’s test with a type that’s not comparable, shall we? The spec tells us “[s]lice, map, and function types are not comparable.” So let’s try with one of those:
var f []int
switch f {
default:
fmt.Println("default")
}
It prints default
. See for yourself.
So what gives? Why didn’t it fail to compile?
If we read just a tiny bit further in the spec’s section about comparable types, we see “as a special case, a slice, map, or function value may be compared to the predeclared identifier nil.”
So actually those types are comparable… but only to a single value: nil
. I’m not sure how much value there is in a switch statement with at most case nil
and default
, but hey… it’s legal.
So how can we trigger this prohibition against non-comparable types? With a type parameter!
Consider this code:
func foo[T any](t T) {
switch t {
case nil:
fmt.Println("nil")
default:
fmt.Println("not nil")
}
}
This code won’t compile at all, and the error tells us why:
./prog.go:12:9: cannot switch on t (variable of type T constrained by any) (T is not comparable)
Quotes from The Go Programming Language Specification Language version go1.22 (Feb 6, 2024)