With Go generics, it is not permitted to check whether a value whose type comes from a type parameter satisfies some optional interface. For example, the following code will not compile (as of Go 1.20):
type Q interface{ Q() }
func G[T any](t T) {
if q, ok := t.(Q); ok {
q.Q()
fmt.Println("Q", q)
}
fmt.Println("G", t)
}
Specifically, the compiler complains:
invalid operation: cannot use type assertion on type parameter value t (variable of type T constrained by any)
This follows from the definition at Type Assertions which says (emphasis mine):
For an expression x of interface type, but not a type parameter, and a type T, the primary expression
x.(T)
asserts that x is not nil and that the value stored in x is of type T. […] If T is an interface type,x.(T)
asserts that the dynamic type of x implements the interface T.
The exemption of type parameters permits the compiler to reject x
whose type comes from a type parameter.
We can work around this, however, by introducing a temporary variable that is of interface type:
func F[T any](t T) {
var v any = t // v is type any, not just a type constrained by any
if q, ok := v.(Q); ok { // N.B. type assertion is on v
q.Q()
fmt.Println("Q", q)
}
fmt.Println("F", t)
}
This example demonstrates that this version correctly handles both a type that implements the optional Q interface, and one that does not.