Home > front end >  Getting field by name using reflect panics when checking IsZero
Getting field by name using reflect panics when checking IsZero

Time:10-29

I have a piece of reflection code that attempts to get the field on a struct by name and then checks if the field exists:

type test struct {
   A bool
   B bool
}

t := new(test)
metaValue := reflect.ValueOf(t).Elem()
field := metaValue.FieldByName(name)
if field.IsZero() {
    glog.Errorf("Field %s was not on the struct", inner)
}

According to the documentation on FieldByName, this function should return a zero value if no field was found. However, the very next line panics with the error:

panic: reflect: call of reflect.Value.IsZero on zero Value

goroutine 268 [running]:
reflect.Value.IsZero({0x0, 0x0, 0x112a974})
        reflect/value.go:1475  0x27f

According to this GitHub issue, this should only happen if the Value contains nil (i.e. no type) and IsValid should be used instead. Why is this happening?

CodePudding user response:

Value.IsZero() reports whether the wrapped value is the zero value of its type. This is not the same as the reflect.Value itself being zero (zero value of reflect.Value which is a struct).

Also note that t in your code is not a struct value, its a pointer to struct. Use Value.Elem() to nagivate to the wrapped struct value (or don't start from a pointer).

If the field does not exist, Value.FieldByName() returns the zero value of reflect.Value, not a non-zero reflect.Value holding the zero value of some type; there is no type info if a field is not found.

So to check if the field does not exist, check if the reflect.Value itself is zero, by comparing it to reflect.Value{}:

if field == (reflect.Value{}) {
    log.Printf("Field %s was not on the struct", name)
}

Testing it:

type test struct {
    A bool
    B bool
    x bool
}

v := new(test)
metaValue := reflect.ValueOf(v).Elem()

for _, name := range []string{"A", "x", "y"} {
    field := metaValue.FieldByName(name)
    if field == (reflect.Value{}) {
        log.Printf("Field %s was not on the struct", name)
    }
}

This will output (try it on the Go Playground):

2009/11/10 23:00:00 Field y was not on the struct
  • Related