【问题标题】:How to initialize nil slices in a struct using reflect如何使用反射初始化结构中的零切片
【发布时间】:2021-02-19 02:47:15
【问题描述】:

对于任何给定的结构,我想遍历其字段并将任何 nil 切片设置为空切片。但是,切片是不可寻址的,因此不可设置。如何设置任何 nil 切片的值?

示例: 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))
        }
    }
}

【问题讨论】:

  • 我很好奇您为什么要这样做 - nil 切片和 0 长度切片之间的差异非常罕见。
  • 我试图使用一个打印出空配置的包。但由于某种原因,它不适用于 nil 切片。最终使用了不同的包...

标签: go struct reflection slice


【解决方案1】:

如果你传递了foo,你不能更新/修改initNilSlices()中的foo,因为那将是一个副本,你只能修改副本(而不是原始值)。

这是错误消息“提示”的内容:

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

您从非指针值中获得了reflect.Value,甚至reflect.ValueOf() 获得的是一个副本,因此它不允许您修改它,因为它不是您想要的。

你必须传递foo的地址:

initNilSlices(&foo)

initNilSlices() 中使用Value.Elem()

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

这样它就可以工作并输出(在Go Playground上试试):

true
false

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-21
    • 1970-01-01
    • 1970-01-01
    • 2018-04-21
    • 2017-07-23
    • 2018-01-20
    相关资源
    最近更新 更多