F21
F21

Reputation: 33431

How do I use reflect to check if the type of a struct field is interface{}?

I am using the reflect package to determine the type of a struct field is interface{}

I want to do the comparison like so (where t is a reflect.Type):

if  t == reflect.TypeOf(interface{}) {

}

The problem is that the compiler complains: type interface {} is not an expression.

Is there anyway to check if the type of a struct field is an interface{}?

Upvotes: 3

Views: 18918

Answers (2)

Christian
Christian

Reputation: 3721

You can get the type of the interface Y by creating a nil instance and using reflection:

yType := reflect.TypeOf((*Y)(nil)).Elem()

and then use the expression

reflect.TypeOf(x).Implements(yType)

to check if the type implements the interface.

Interfaces themselves can not be instantiated. The interface{} interface which is the empty interface is implemented by all types so all fields implement that.

https://play.golang.org/p/gRfheIW_9Y

Actually it also works with the empty interface{} itself but this will always return true (if i'm not missing something):

https://play.golang.org/p/29rWP4LtIo

Upvotes: 7

icza
icza

Reputation: 418505

interface{} is a type, and reflect.TypeOf() expects a value. So you can't pass the literal interface{} to it. You can only pass a value.

Back to the original question. Let's see a struct example:

type My struct {
    A int
    B interface{}
    C io.Reader
}

You want to tell if the type of a field is interface{}. Acquire the reflect.Type of the struct type, then you can access the fields using Type.Field() or Type.FieldByName().

This gives you a value of type reflect.StructField which stores the type of the field.

So far so good. But what should we compare it to? interface{} is an interface type with 0 methods. You can't have (instantiate) a value of that type. You can only have values of concrete types, but yes, they may be wrapped in an interface type.

You could use Type.Kind, and compare it to reflect.Interface, which tells you if it's an interface, but this is true for all interface types. You could also check if it has 0 methods with Type.NumMethod(), which must be 0 for interface{}, but other interfaces could also have 0 methods...

You may use Type.Name, but since interface{} is a unnamed type, its name is the empty string "" (and there are other unnamed types). You may use Type.String() which returns "interface {}" for the empty interface:

t := reflect.TypeOf(My{})

for i := 0; i < t.NumField(); i++ {
    f := t.Field(i)
    fmt.Printf("Field %q, type: %-12v, type name: %-8q, is interface{}: %v\n",
        f.Name, f.Type,
        f.Type.Name(),
        f.Type.String() == "interface {}",
    )
}

Output (try it on the Go Playground):

Field "A", type: int         , type name: "int"   , is interface{}: false
Field "B", type: interface {}, type name: ""      , is interface{}: true
Field "C", type: io.Reader   , type name: "Reader", is interface{}: false

You might find this related question interesting / useful: Identify non builtin-types using reflect

Upvotes: 6

Related Questions