I'm always interested to see what the Go developers are doing with generic types in the standard library. One such development I've noticed recently is a new generic function in the 'reflect' package,
reflect.TypeFor()
; this will likely appear as part of Go 1.22. What TypeFor() does is relatively straightforward; it returns the
reflect.Type
of its type, which you can then use either for further reflection or to compare it to some other type (which you will likely have obtained through reflection).
The reflect package already had a
reflect.TypeOf()
function, but because it wasn't generic the usage was more awkward. A good example of how the change improves the readability is in net/rpc/server.go , where net/rpc needs to check to see if a method returns an
error
, which requires knowing the type of '
error
' for reflection purposes. The old code to do this with TypeOf() was:
var typeOfError = reflect.TypeOf((*error)(nil)).Elem()
The new code using TypeFor() is simpler and more obvious:
var typeOfError = reflect.TypeFor[error]()
The old code is awkward partly because of interfaces. Because
reflect.TypeOf()
is passed an '
interface{}
' (these days also known as '
any
'), it can't directly give you the
reflect.Type
of an interface, because that interface type will be lost when it's converted to '
interface{}
'. Instead
reflect.TypeOf()
returns the underlying non-interface type (or nil). As we've seen in the context of '
nil
' being only sort of typed , to get around this you must pass a pointer to the interface (well, a value of the interface), get back the type 'pointer to <some interface type>', and then dereference to the original type through
reflect
again, which is what the original code is doing.
You might reasonably wonder how
reflect.TypeFor()
works, and if it has some special internal trick to access the type of interface types. The answer turns out to be no. In fact the current version in reflect/type.go is simply what the
TypeOf()
version was doing, generalized:
func TypeFor[T any]() Type {
return TypeOf((*T)(nil)).Elem()
}
In Go, sometimes there is no trick, even in the
reflect
package.