简体   繁体   中英

How to initialize nil slices in a struct using reflect

For any given struct, I want to loop over its fields and set any nil slices to an empty slice. However, slices are unaddressable and hence not settable. How can I set the values of any nil slices?

Example: https://goplay.space/#iV6OHkYVTru

package main

import (
    "fmt"
    "reflect"
)

type Foo struct {
    IntSlice []int
    StrSlice []string
}

func main() {
    foo := Foo{}
    fmt.Println(foo.IntSlice == nil)
    initNilSlices(foo)
    fmt.Println(foo.IntSlice == nil)
}

func initNilSlices(x interface{}) {
    v := reflect.ValueOf(x)
    for i := 0; i < v.NumField(); i++ {
        f := v.Field(i)
        if f.Kind() == reflect.Slice {
            t := f.Type()
            f.Set(reflect.MakeSlice(t, 0, 0))
        }
    }
}

You can't update / modify foo in initNilSlices() if you pass foo because that will be a copy, and you could only modify the copy (and not the original value).

This is what the error message "hints":

panic: reflect: reflect.Value.Set using unaddressable value

You obtained the reflect.Value from a non-pointer value, and even what reflect.ValueOf() gets is a copy, so it doesn't allow you to modify it because it wouldn't be what you'd want.

You have to pass the address of foo :

initNilSlices(&foo)

And in initNilSlices() use Value.Elem() :

v := reflect.ValueOf(x).Elem()

With this it works and outputs (try it on the Go Playground ):

true
false

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM