Go 如何使用reflect更改结构切片中的字段?

Go 如何使用reflect更改结构切片中的字段?,go,Go,我有以下几点 主程序包 进口( “fmt” “反映” ) 类型A结构{ 名称字符串 年龄智力 } func change(接口{}){ aa:=反映间接(反映(a)的值) 对于i:=0;i

我有以下几点

主程序包
进口(
“fmt”
“反映”
)
类型A结构{
名称字符串
年龄智力
}
func change(接口{}){
aa:=反映间接(反映(a)的值)
对于i:=0;i
正如您所看到的,有些变量是空片,有些则不是。对于那些为空的,我需要添加1个{“fred”,54}结构。对于那些不是空的切片,我需要将所有值更改为{“fred”,54}。我事先不知道字段是什么…只是如果有一个字符串字段,那么值应该是“fred”,如果是int字段,那么值应该是54


我可以更改“a”的值,但其他所有操作都会因“panic:reflect:调用slice value上的reflect.value.NumField”而失败。我不知道该怎么办。谢谢大家!

如注释中所述,您不能在片上使用
NumField
,因为该方法仅适用于
reflect.Value
s类
reflect.Struct

所以,如果你想处理这两种情况,你需要知道哪一种是传入的

if rv.Kind() == reflect.Struct {
    changeStruct(rv)
}
if rv.Kind() == reflect.Slice {
    changeSlice(rv)
}
现在,如果您想要附加到一个空的切片,您要么传入一个指向该切片的指针,要么返回新切片

change(&b)
change(&c)
此外,为了能够初始化要附加的单个元素,您首先需要知道其类型,要获取切片元素的类型,您首先要获取切片的
reflect.type
,然后使用其
Elem
方法获取切片元素的类型。对于该类型,您可以使用
reflect.New
分配该类型的新值并将其附加到切片

var elem reflect.Value

// rv is the slice
typ := rv.Type().Elem()
if typ.Kind() == reflect.Ptr {
    elem = reflect.New(typ.Elem())
}
if typ.Kind() == reflect.Struct {
    elem = reflect.New(typ).Elem()
}
然后可以使用
reflect.Value.Len
reflect.Value.Index
方法在片上循环

ln := rv.Len()
for i := 0; i < ln; i++ {
    changerv(rv.Index(i))
}
ln:=rv.Len()
对于i:=0;i

守则:

func change(a interface{}) {
    rv := reflect.ValueOf(a)
    changerv(rv)
}

func changerv(rv reflect.Value) {
    if rv.Kind() == reflect.Ptr {
        rv = rv.Elem()
    }

    if rv.Kind() == reflect.Struct {
        changeStruct(rv)
    }
    if rv.Kind() == reflect.Slice {
        changeSlice(rv)
    }
}

// assumes rv is a slice
func changeSlice(rv reflect.Value) {
    ln := rv.Len()
    if ln == 0 && rv.CanAddr() {
        var elem reflect.Value

        typ := rv.Type().Elem()
        if typ.Kind() == reflect.Ptr {
            elem = reflect.New(typ.Elem())
        }
        if typ.Kind() == reflect.Struct {
            elem = reflect.New(typ).Elem()
        }

        rv.Set(reflect.Append(rv, elem))
    }

    ln = rv.Len()
    for i := 0; i < ln; i++ {
        changerv(rv.Index(i))
    }
}

// assumes rv is a struct
func changeStruct(rv reflect.Value) {
    if !rv.CanAddr() {
        return
    }
    for i := 0; i < rv.NumField(); i++ {
        field := rv.Field(i)

        switch field.Kind() {
        case reflect.String:
            field.SetString("fred")
        case reflect.Int:
            field.SetInt(54)
        default:
            fmt.Println("unknown field")
        }
    }
}
func-change(一个接口{}){
rv:=反射值(a)
变更rv(rv)
}
func changerv(rv反射值){
如果rv.Kind()==reflect.Ptr{
rv=rv.Elem()
}
如果rv.Kind()==reflect.Struct{
变更结构(rv)
}
如果rv.Kind()==reflect.Slice{
变更切片(rv)
}
}
//假设rv是一个切片
func changeSlice(rv反射值){
ln:=rv.Len()
如果ln==0&&rv.CanAddr(){
变量元素反映值
类型:=rv.Type().Elem()
如果type.Kind()==reflect.Ptr{
elem=reflect.New(典型的elem())
}
如果type.Kind()==reflect.Struct{
elem=reflect.New(典型).elem()
}
rv.集合(反射.附加(rv,元素))
}
ln=rv.Len()
对于i:=0;i

如注释中所述,

不能在片上使用
NumField
,因为该方法仅适用于
reflect.Value
s类
reflect.Struct

所以,如果你想处理这两种情况,你需要知道哪一种是传入的

if rv.Kind() == reflect.Struct {
    changeStruct(rv)
}
if rv.Kind() == reflect.Slice {
    changeSlice(rv)
}
现在,如果您想要附加到一个空的切片,您要么传入一个指向该切片的指针,要么返回新切片

change(&b)
change(&c)
此外,为了能够初始化要附加的单个元素,您首先需要知道其类型,要获取切片元素的类型,您首先要获取切片的
reflect.type
,然后使用其
Elem
方法获取切片元素的类型。对于该类型,您可以使用
reflect.New
分配该类型的新值并将其附加到切片

var elem reflect.Value

// rv is the slice
typ := rv.Type().Elem()
if typ.Kind() == reflect.Ptr {
    elem = reflect.New(typ.Elem())
}
if typ.Kind() == reflect.Struct {
    elem = reflect.New(typ).Elem()
}
然后可以使用
reflect.Value.Len
reflect.Value.Index
方法在片上循环

ln := rv.Len()
for i := 0; i < ln; i++ {
    changerv(rv.Index(i))
}
ln:=rv.Len()
对于i:=0;i

守则:

func change(a interface{}) {
    rv := reflect.ValueOf(a)
    changerv(rv)
}

func changerv(rv reflect.Value) {
    if rv.Kind() == reflect.Ptr {
        rv = rv.Elem()
    }

    if rv.Kind() == reflect.Struct {
        changeStruct(rv)
    }
    if rv.Kind() == reflect.Slice {
        changeSlice(rv)
    }
}

// assumes rv is a slice
func changeSlice(rv reflect.Value) {
    ln := rv.Len()
    if ln == 0 && rv.CanAddr() {
        var elem reflect.Value

        typ := rv.Type().Elem()
        if typ.Kind() == reflect.Ptr {
            elem = reflect.New(typ.Elem())
        }
        if typ.Kind() == reflect.Struct {
            elem = reflect.New(typ).Elem()
        }

        rv.Set(reflect.Append(rv, elem))
    }

    ln = rv.Len()
    for i := 0; i < ln; i++ {
        changerv(rv.Index(i))
    }
}

// assumes rv is a struct
func changeStruct(rv reflect.Value) {
    if !rv.CanAddr() {
        return
    }
    for i := 0; i < rv.NumField(); i++ {
        field := rv.Field(i)

        switch field.Kind() {
        case reflect.String:
            field.SetString("fred")
        case reflect.Int:
            field.SetInt(54)
        default:
            fmt.Println("unknown field")
        }
    }
}
func-change(一个接口{}){
rv:=反射值(a)
变更rv(rv)
}
func changerv(rv反射值){
如果rv.Kind()==reflect.Ptr{
rv=rv.Elem()
}
如果rv.Kind()==reflect.Struct{
变更结构(rv)
}
如果rv.Kind()==reflect.Slice{
变更切片(rv)
}
}
//假设rv是一个切片
func changeSlice(rv反射值){
ln:=rv.Len()
如果ln==0&&rv.CanAddr(){
变量元素反映值
类型:=rv.Type().Elem()
如果type.Kind()==reflect.Ptr{
elem=reflect.New(典型的elem())
}
如果type.Kind()==reflect.Struct{
elem=reflect.New(典型).elem()
}
rv.集合(反射.附加(rv,元素))
}
ln=rv.Len()
对于i:=0;i