假设我有某种类型,并且我想实例化此类型的变量,并且每个值都不为nil。
type Event struct {
HappenedAtMs int64
ReceivedAtMs int64
FieldA *FieldAType
FieldB []*FieldBType
这是我目前正在尝试的方法:
eventFields := reflect.TypeOf(Event{})
event := Event{}
for i := 0; i < eventFields.NumField(); i++ {
nonEmptyType := reflect.New(eventFields.Field(i).Type).Elem()
reflect.ValueOf(&event).Elem().Field(i).Set(nonEmptyType)
}
但是,运行此代码后,事件变量中的所有字段仍设置为nil。我怎样才能实现自己想要的?
最佳答案
reflect
包需要一个指向该结构的指针,以便它能够设置其字段。还需要导出字段,您可以使用CanSet
方法进行检查。
要使用reflect
初始化指针类型,您只需执行reflect.New(T.Elem())
即可。要将map
,slice
,func
或chan
类型初始化为nonnil,可以分别使用MakeMap
,MakeSlice
,MakeFunc
和MakeChan
函数。要将接口(interface)类型初始化为非nil,可以使用reflect.StructOf
创建一个匿名结构类型,并在目标接口(interface)类型的单个嵌入字段中嵌入该接口(interface)类型,从而使结构类型自动满足该接口(interface)的要求,并且该接口(interface)的实例可以是用于将字段设置为非零。
event := Event{}
rv := reflect.ValueOf(&event).Elem()
for i := 0; i < rv.NumField(); i++ {
if f := rv.Field(i); isNilable(f) && f.IsNil() && f.CanSet() {
switch f.Kind() {
case reflect.Ptr:
f.Set(reflect.New(f.Type().Elem()))
case reflect.Slice:
f.Set(reflect.MakeSlice(f.Type(), 0, 0))
case reflect.Interface:
sf := reflect.StructField{
Name: f.Type().Name(),
Type: f.Type(),
Anonymous: true,
}
rt := reflect.StructOf([]reflect.StructField{sf})
f.Set(reflect.New(rt).Elem())
// TODO handle the rest of nilable types
}
}
}
https://play.golang.com/p/nQqvUIROqF-