More live coding today! Join me! And bring your questions.
Type switches
…
A type parameter or a generic type may be used as a type in a case. If upon instantiation that type turns out to duplicate another entry in the switch, the first matching case is chosen.
func f[P any](x any) int { switch x.(type) { case P: return 0 case string: return 1 case []P: return 2 case []byte: return 3 default: return 4 } } var v1 = f[string]("foo") // v1 == 0 var v2 = f[byte]([]byte{}) // v2 == 2
The example included is nice, because it shows two examples of the type parameter P
being used: Both the first case (case P
) and third (case []P
) use the type parameter.
But notice that this is distinctly different from using a type switch to determine the underlying type of a type parameter. We already talked about this briefly, but I think a recap is in order. Consider the following function signature:
func f[P int | float64](x P) int {
We could use the above construct, and include P
in a type switch case:
switch y := x.(type) {
case P:
However, here y
is of type P
, not specifically of type int
or float64
. If you want to determine which underlying type P
has, we need to use a different trick:
switch y := any(x).(type) {
case int:
/* y is of type int */
case float64:
/* y is of type float64 */
}
The trick is to convert x
(of type P
) to an empty interface (that’s what any(x)
) does, then we can pass that value to a type switch (or type conversion), to get at the underlying type.
Quotes from The Go Programming Language Specification Language version go1.22 (Feb 6, 2024)