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

上下文:我正在尝试使用 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,或者我创建了不正确的切片类型,这就是我的问题的根源吗?


天涯尽头无女友
浏览 156回答 2
2回答

杨__羊羊

当你发现 put 元素是一个指针时,你必须创建一个指针指向的类型的实例,但你正在创建一个新指针。试试这个:if newC.Kind() == reflect.Ptr {&nbsp; &nbsp; ncInt := reflect.New(newC.Type().Elem())&nbsp; &nbsp; newC = ncInt.Elem()}

DIEA

一种简单的方法是编写一个函数,用随机数据填充 reflect.Value。该函数为结构化值(切片、结构......)递归调用自身。func randFillValue(v reflect.Value) {&nbsp; &nbsp; switch v.Kind() {&nbsp; &nbsp; case reflect.Ptr:&nbsp; &nbsp; &nbsp; &nbsp; v.Set(reflect.New(v.Type().Elem()))&nbsp; &nbsp; &nbsp; &nbsp; randFillValue(v.Elem())&nbsp; &nbsp; case reflect.Struct:&nbsp; &nbsp; &nbsp; &nbsp; for i := 0; i < v.NumField(); i++ {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; randFillValue(v.Field(i))&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; case reflect.Slice:&nbsp; &nbsp; &nbsp; &nbsp; num := rand.Intn(10)&nbsp; &nbsp; &nbsp; &nbsp; v.Set(reflect.MakeSlice(v.Type(), num, num))&nbsp; &nbsp; &nbsp; &nbsp; for i := 0; i < num; i++ {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; randFillValue(v.Index(i))&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; case reflect.Int:&nbsp; &nbsp; &nbsp; &nbsp; v.SetInt(10)&nbsp; // TODO: fill with random int&nbsp; &nbsp; case reflect.String:&nbsp; &nbsp; &nbsp; &nbsp; v.SetString("random string") // TODO: fill with random string&nbsp; &nbsp; }&nbsp; &nbsp; // TODO: add other reflect.Kind}// randFill fills the value pointed to pv with random values.func randFill(pv interface{}) {&nbsp; &nbsp; randFillValue(reflect.ValueOf(pv).Elem())}在操场上运行它。与问题中的代码相比,此代码中有一些简化。首先是这个答案通过使用来避免reflect.ValueOfand.Interface()调用reflect.Value。第二个是指针作为顶级案例处理,从而消除了切片元素和字段代码中指针相关代码的需要。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go