How to switch on reflect.Type?
you may not need reflect if you are just trying to detect type.
switch t := myVar.(type){
case []uint8:
// t is []uint8
case *Foo:
// t is *Foo
default:
panic("unknown type")
}
What are you actually trying to accomplish?
This might work.
switch t := reflect.TypeOf(a).String() {
case "[]uint8":
default:
}
The answer to the initial question How to switch on reflect.Type? is: You can’t. However, you can do it with reflect.Value
.
- Given a variable
v interface{}
you can callreflect.TypeOf(v)
andreflect.ValueOf(v)
, which return areflect.Type
orreflect.Value
, resp.- If the type of
v
is notinterface{}
then these function calls will convert it tointerface{}
.
- If the type of
reflect.Type
contains various run-time information about the type, but it does not contain anything usable to retrieve the type ofv
itself as needed in a type switch.- Hovewer,
reflect.Value
provides it through itsInterface()
method, which returns the underlying value asinterface{}
. This you can use in a type switch or type assertion.
import "fmt"
import "reflect"
var v int
var rt reflect.Type = reflect.TypeOf(v)
fmt.Println(rt.String(), " has awesome properties: Its alignment is",
rt.Align(), ", it has", rt.Size(), "bytes, is it even comparable?",
rt.Comparable())
// … but reflect.Type won’t tell us what the real type is :(
// Let’s see if reflect.Value can help us.
var rv reflect.Value = reflect.ValueOf(v)
// Here we go:
vi := rv.Interface()
switch vi.(type) {
// Mission accomplished.
}
Perhaps it helps to clarify a few points which may cause confusion about dynamic typing in Go. At least I was confused by this for quite some time.
reflect
vs. interface{}
In Go there are two systems of run-time generics:
- In the language:
interface{}
, useful for type switches/assertions, - In the library: The
reflect
package, useful for inspection of run-time generic types and values of such.
These two systems are separated worlds, and things that are possible with one are impossible with the other. For example, Given an interface{}
, it is in plain Go (with safe code) impossible to, say, if the value is an array or slice, regardless of its element type, then get the value of the i-th element. One needs to use reflect
in order to do that. Conversely, with reflect
it is impossible to make a type switch or assertion: convert it to interface{}
, then you can do that.
There are only very few points of an interface between these systems. In one direction it is the TypeOf()
and ValueOf()
functions which accept interface{}
and return a reflect
struct. In the other direction it is Value.Interface()
.
It is a bit counter-intuitive that one needs a Value
, not a Type
, to do a type switch. At least this is somewhat consistent with the fact that one needs a value construct a Type
by calling TypeOf()
.
reflect.Kind
Both reflect.Type
and reflect.Value
have a Kind()
method. Some suggest using the value these methods return, of type reflect.Kind
, to imitate a type switch.
While this may be useful in certain situations, it is not a replacement for a type switch. For example, using Kind
one cannot distinguish between int64
and time.Duration
because the latter is defined as
type Duration int64
Kind
is useful to tell if a type is any kind of struct, array, slice etc., regardless of the types it is composed of. This is not possible to find out with a type switch.
(Side note. I had the same question and found no answer here helpful so I went to figure it out myself. The repeated counter-question “why are you doing this?”, followed by unrelated answers did not help me either. I have a good reason why I want to do it precisely this way.)
First question, are you sure you want to switch on reflect.Type and not use a type switch? Example:
switch x := y.(type) {
case []uint8:
// x is now a []uint8
}
Assuming that will not work for your situation, my recommendation is to make those package variables. Example:
var uint8SliceType = reflect.TypeOf(([]uint8)(nil))
func Foo() {
var t reflect.Type
switch t {
case uint8SliceType:
// handle []uint8 array type
}
}