22

I've tried to identify a struct with string value(name). reflect.TypeOf returns Type.

But type assertion needs a type.

How can I casting Type to type?

Or any suggestion to handle it?

http://play.golang.org/p/3PJG3YxIyf

package main

import (
"fmt"
"reflect"
)
type Article struct {
    Id             int64       `json:"id"`
    Title          string      `json:"title",sql:"size:255"`
    Content        string      `json:"content"`
}


func IdentifyItemType(name string) interface{} {
    var item interface{}
    switch name {
    default:
        item = Article{}
    }
    return item
}

func main() {

    i := IdentifyItemType("name")
    item := i.(Article)
    fmt.Printf("Hello, item : %v\n", item)
    item2 := i.(reflect.TypeOf(i))  // reflect.TypeOf(i) is not a type
    fmt.Printf("Hello, item2 : %v\n", item2)

}
peterh
  • 11,875
  • 18
  • 85
  • 108
dorajistyle
  • 468
  • 1
  • 5
  • 14
  • 9
    This is completely impossible in Go. A type assertion asserts a compile-time-constant fixed static type only. You have to rework your solution. – Volker Jan 12 '15 at 11:50

6 Answers6

10

If you need to switch on the type of the outer interface{} you wont need reflection.

switch x.(type){
  case int: 
    dosomething()
}

...but if you need to switch on the type of the attributes in an interface then you can do this:

s := reflect.ValueOf(x)
for i:=0; i<s.NumValues; i++{
  switch s.Field(i).Interface().(type){
    case int: 
      dosomething()
  }
}

I haven't found a cleaner way, I'd love to know if it exists.

MondayPaper
  • 1,569
  • 1
  • 15
  • 20
  • But this is for determined types only, not custom type. What if i want to do type assertion for custom struct types? – TomSawyer Mar 13 '18 at 15:20
  • In my second example, you can reflect on any struct. The "int" is just an example of discovering attributes on the struct as it loops over each attribute. – MondayPaper Mar 22 '18 at 19:51
  • I mean we still have to iterate every type we have. There's no way to use type of `reflect.TypeOf` then use it for type casting or type casting by string x.("customtype") – TomSawyer Mar 23 '18 at 02:41
  • Nope, you'd need generics for that :( – MondayPaper Mar 26 '18 at 16:40
9

A type assertion, syntactically, takes a type in the parentheses, not an expression. So it is a syntax error.

You seem to be trying to do a type assertion with a value computed at runtime. Does that make sense? Let's think about what a type assertion is.

A type assertion consists of two things:

  1. At compile time: It causes the resulting expression to have the desired compile-time type. The expression x.(T) has compile-time type T. This allows you to do stuff the expression that you can do with type T, which you may not be able to do with the type of x.
  2. At runtime: It checks whether the value is not nil and is actually of the given type, and if not, it causes a panic.

The first part obviously doesn't make sense for a type computed at runtime. The compile-time type of the resulting expression cannot depend on something that is not known at compile-time.

The second one (runtime check) can be done with a type computed at runtime. Something like:

if reflect.TypeOf(x) != someTypeComputedAtRuntime {
    panic(42)
}
newacct
  • 119,665
  • 29
  • 163
  • 224
6

Lots of things, but basically "it doesn't work that way". The thing inside the parentheses in a type assertion needs to be a type, that is a type name or a type literal. reflect.TypeOf(i) isn't one of those, it's a method call expression. Therefore this is a syntax error. reflect.TypeOf doesn't "return a type" (which isn't really a thing you can do in Go), it returns a reflect.Type, which is an ordinary go struct that contains information about a type (i.e. sort of a meta-type).

But the more fundamental reason why it doesn't work is because it can't... Go needs to know what the type of a variable is when it's declared. Either its type is given explicitly in a var declaration, or it's inferred from the type of the initialization value in a var x = value declaration or x := value short assignment. It is not possible for the type to be unknown at compile time. Go doesn't let you write an expression that produces an undetermined type.

The very purpose of a type assertion is to take a value of an interface type (which is a kind of "box" that can hold values of multiple types, or for interface{}, any type at all) and retrieve a value of a specific concrete type. The value produced by the assertion will have the type named by the assertion, and no other. (In the case of a ,ok assignment, if the assertion fails, the variable will hold a zero value but still be of the correct type). If you could write an assertion to a type that was known only at runtime, the whole thing would fall apart, so you can't write it — it's an error.

In short, you can't use reflection to do that. You can use reflect to learn what the type of i is, you can learn that type's name, you can learn that its underlying Kind is Struct, you can enumerate the struct's fields and get the values out of them, etc... all of these are legitimate uses of reflection. But it can't give you back a variable of type MyStruct — the way to do that is i.(MyStruct).

hobbs
  • 223,387
  • 19
  • 210
  • 288
3

I think what you're looking for here is a type switch. https://tour.golang.org/methods/16

Roberto
  • 1,944
  • 1
  • 30
  • 42
Nano
  • 51
  • 2
2

If you can handle the noise and implement an extra method which all the types implement e.g. 'Type() string', you can do something like this:

        ve := &ValidationError{}
        nf := &NotFound{}

        switch err.Type() {
        case ve.Type() :
            SendBadRequest(w, err)
        case nf.Type() :
            http.NotFound(w, r)
        default:
            SendInternalError(w, err)
        }
rjarmstrong
  • 1,221
  • 12
  • 22
-3

I think you can use ValueOf to solve this

item2 :=  reflect.ValueOf(i)
fmt.Printf("Hello, item2 : %v\n", item2)
Pedro Fillastre
  • 892
  • 6
  • 10
  • 3
    ValueOf() returns a type reflect.Value not the actual underlying type of the interface... – prl900 Jun 09 '16 at 13:36