2

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?

1
  • 1
    Just a tip: avoid using new(T) as much as possible. It's better to just create a new literal (t := test{} or t := &test{}). There are certain cases where the use of new makes sense, but those are few and far between Commented Oct 28, 2021 at 8:32

1 Answer 1

1

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
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.