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 call reflect.TypeOf(v) and reflect.ValueOf(v), which return a reflect.Type or reflect.Value, resp.
    • If the type of v is not interface{} then these function calls will convert it to interface{}.
  • reflect.Type contains various run-time information about the type, but it does not contain anything usable to retrieve the type of v itself as needed in a type switch.
  • Hovewer, reflect.Value provides it through its Interface() method, which returns the underlying value as interface{}. 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
    }

}

Tags:

Reflection

Go