为了账号安全,请及时绑定邮箱和手机立即绑定

用反射遍历结构,用反射创建新的指针类型切片

用反射遍历结构,用反射创建新的指针类型切片

Go
天涯尽头无女友 2022-05-05 15:59:30
上下文:我正在尝试使用 any struct,并用随机数据填充它。目前我最大的症结是,如果 astruct有一个字段是指针类型的切片(即。[]*Foo),我无法弄清楚如何使用反射为该结构创建数据。这是我的功能目前的样子:func randFill(in interface{}) interface{} {    t := reflect.TypeOf(in)    v := reflect.ValueOf(in)    if v.Kind() == reflect.Ptr {        v = v.Elem()    }    switch v.Kind() {    case reflect.Struct:        newStr := reflect.New(t).Elem()        for i := 0; i < t.NumField(); i++ {            newV := randFill(reflect.New(t.Field(i).Type).Interface())            newStr.Field(i).Set(reflect.ValueOf(newV))        }        return newStr.Interface()    case reflect.Slice:        num := rand.Intn(10)        slice := reflect.MakeSlice(v.Type(), num, num)        for j := 0; j < num; j++ {            newC := slice.Index(j)            if newC.Kind() == reflect.Ptr {                ncInt := reflect.New(newC.Type())                newC = ncInt.Elem()            }            gen := randFill(newC.Interface())            slice.Index(j).Set(reflect.ValueOf(gen))        }        return slice.Interface()    //    // ... there are other cases down here for handling primitives    //    }    return nil}这在没有指针类型的切片上效果很好,但这里有一个它遇到问题的结构的示例:type Parent struct {    Name     string    Age      int    Children []*Child}type Child struct {    Name string    Age  int}如果我创建了 aParent{}并将其传递给randFill(Parent{}),则它无法生成值,*Child因为当它到达这一行时:newC := slice.Index(j)此时的值,newC在处理 的切片时,[]*Child是(*Child)(nil)一个reflect.Value类型。newC := slice.Index(j)fmt.Printf("%#v, %T", newC, newC) // Outputs: (*Child)(nil), reflect.Value在能够从 a 初始化指针类型时,我缺少一些东西reflect.Value,或者我创建了不正确的切片类型,这就是我的问题的根源吗?
查看完整描述

2 回答

?
杨__羊羊

TA贡献1943条经验 获得超7个赞

当你发现 put 元素是一个指针时,你必须创建一个指针指向的类型的实例,但你正在创建一个新指针。试试这个:


if newC.Kind() == reflect.Ptr {

    ncInt := reflect.New(newC.Type().Elem())

    newC = ncInt.Elem()

}


查看完整回答
反对 回复 2022-05-05
?
DIEA

TA贡献1820条经验 获得超2个赞

一种简单的方法是编写一个函数,用随机数据填充 reflect.Value。该函数为结构化值(切片、结构......)递归调用自身。


func randFillValue(v reflect.Value) {

    switch v.Kind() {

    case reflect.Ptr:

        v.Set(reflect.New(v.Type().Elem()))

        randFillValue(v.Elem())

    case reflect.Struct:

        for i := 0; i < v.NumField(); i++ {

            randFillValue(v.Field(i))

        }

    case reflect.Slice:

        num := rand.Intn(10)

        v.Set(reflect.MakeSlice(v.Type(), num, num))

        for i := 0; i < num; i++ {

            randFillValue(v.Index(i))

        }

    case reflect.Int:

        v.SetInt(10)  // TODO: fill with random int

    case reflect.String:

        v.SetString("random string") // TODO: fill with random string

    }

    // TODO: add other reflect.Kind

}


// randFill fills the value pointed to pv with random values.

func randFill(pv interface{}) {

    randFillValue(reflect.ValueOf(pv).Elem())

}

在操场上运行它。


与问题中的代码相比,此代码中有一些简化。首先是这个答案通过使用来避免reflect.ValueOfand.Interface()调用reflect.Value。第二个是指针作为顶级案例处理,从而消除了切片元素和字段代码中指针相关代码的需要。


查看完整回答
反对 回复 2022-05-05
  • 2 回答
  • 0 关注
  • 155 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信