6

I'm writing a recursive function that iterates through every primitive field in a struct.

I need to be able to support fields that are structs, pointers to structs, fields, and pointers to fields.

I've tried doing something like this, where for each field, I first do a check if it's a pointer. If it is, I switch on the type of that instead of just the field itself.

//Get reflect values and types
valOf := reflect.ValueOf(dest).Elem()
typeOf := valOf.Type()

//Iterate through each field
for i := 0; i < valOf.NumField(); i++ {

    var fieldValDeref reflect.Value

    //Get reflect value and type of single field
    fieldVal := valOf.Field(i)
    fieldTyp := typeOf.Field(i)

    //Check if field is a pointer. If so, dereference and switch on dereferenced type
    if fieldVal.Kind() == reflect.Ptr {
        fieldValDeref = fieldVal.Elem()
    } else {
        fieldValDeref = fieldVal
    }


    switch fieldValDeref.Kind() {
    case reflect.Array, reflect.Chan, reflect.Interface, reflect.Func, reflect.Map, reflect.UnsafePointer:
        return errors.New("invalid destination field: " + fieldTyp.Name)

    case reflect.Struct:
        //Recursive call
        break
    default:
        //Perform Action on Field
..................................

The issue I'm getting with this, is that the type of any pointer, struct or not, after calling .Elem() is reflect.Invalid.

How can I first dereference a field (if it is a pointer) and then perform actions accordingly, whether the field is a struct or a primitive?

Thanks

5
  • 3
    Dereferencing an uninitialized, ie nil, pointer will always result in reflect.Invalid. See here (play.golang.com/p/8UgDtqK_8ra). To avoid this you have to initialize the field's value which you can do with reflect.New Commented Jan 2, 2019 at 20:54
  • ... here's an example: play.golang.com/p/q71J0qTQECP Commented Jan 2, 2019 at 20:58
  • Would reflectively creating a zero value instance of it first before dereferencing solve this? Commented Jan 2, 2019 at 20:59
  • Does the code in the second comment not already answer your question? Commented Jan 2, 2019 at 21:03
  • 1
    It does, thanks. Comments didn't refresh when I replied. Commented Jan 2, 2019 at 21:11

1 Answer 1

8

As mkopriva mentioned, dereferencing a nil pointer will always return reflect.Invalid. The solution is to create a new instance first.

if fieldVal.Kind() == reflect.Ptr {
    fieldVal.Set(reflect.New(fieldVal.Type().Elem()))
    fieldValDeref = fieldVal.Elem()
} else {
    fieldValDeref = fieldVal
}
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.