上下文:我正在尝试获取任何struct
,并用随机数据填充它。
此刻,我最大的障碍是,如果struct
的字段是具有指针类型的切片(即[]*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
}
如果我创建了一个Parent{}
并将其传递给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
我无法从reflect.Value
初始化指针类型,或者我创建的切片类型不正确,这就是问题的根源吗?
答案 0 :(得分:1)
当发现放置元素是一个指针时,必须创建该指针指向的类型的实例,但是您正在创建一个新的指针。试试这个:
if newC.Kind() == reflect.Ptr {
ncInt := reflect.New(newC.Type().Elem())
newC = ncInt.Elem()
}
答案 1 :(得分:1)
一种简单的方法是编写一个用随机数据填充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.ValueOf
一起使用避免了.Interface()
和reflect.Value
的调用。第二个问题是将指针作为顶级案例处理,从而消除了slice元素和域代码中与指针相关的代码的需要。