Type switches
…
Cases then match actual types
T
against the dynamic type of the expressionx
. As with type assertions,x
must be of interface type, but not a type parameter, and each non-interface typeT
listed in a case must implement the type ofx
. The types listed in the cases of a type switch must all be different.TypeSwitchStmt = "switch" [ SimpleStmt ";" ] TypeSwitchGuard "{" { TypeCaseClause } "}" . TypeSwitchGuard = [ identifier ":=" ] PrimaryExpr "." "(" "type" ")" . TypeCaseClause = TypeSwitchCase ":" StatementList . TypeSwitchCase = "case" TypeList | "default" .
There are many details in that paragraph, and some subtleties that are easy to miss. So let’s tear this apart bit by bit. Today, we’ll look at this phrase:
x
must be of interface type
This refers to the example we saw yesterday: switch x.(type) {
. In other words, this is invalid, and won’t compile:
var x int
switch x.(int) {
}
This might seem obvious, and non-problematic, but it can be a problem when you’re in a generic function:
func toBool[T string|bool](in T) bool {
switch t := in.(type) {
case string:
v, _ := strconv.ParseBool(t)
return v
case bool:
return t
}
return false
}
So what’s the solution? Well, fortunately, it’s quite trivial to convert a non-interface value to an interface. Simply replace in
with any(in)
(or interface{}(in)
if you’re using Go 1.17 or older). Now it works!.
Quotes from The Go Programming Language Specification Language version go1.22 (Feb 6, 2024)