在Go中使用反射设置嵌套结构域的值

时间:2018-09-17 13:44:23

标签: go reflection protocol-buffers

我正在尝试用一个

创建protobuf结构
type FlatMessage map[string][]byte

,我正在努力设置嵌套字段的值。

我有一个

func (fm *FlatMessage) Unflatten() (pb.Message, error)

将平面消息转换为结构化protobuf的方法。

我还有一个名为analyze的辅助函数,该函数采用类型pb.Message的结构并返回一个map[int]*ProtoField,其中:

type ProtoField struct {
    Name  string
    Type  reflect.Type
}

analyze递归遍历pb.Message并收集我需要的所有信息。到目前为止,一切都很好。

现在,当我通过FlatMessage逐个密钥输入时,密钥是相应protobuf字段的编码字段编号,我可以使用反射进行设置,如下所示:

r := reflect.ValueOf(&result).Elem().FieldByName(field.Name)
if r.IsValid() {
    r.Set(scalarValue)
}

,但是仅当所讨论的field.Name不引用嵌套字段(即设置OldV1Id可以正常工作,但尝试设置Profile.Id或{{ 1}},结果为:

Destination.Address.TypeOfNumber

我知道这是由于这样的事实,当我的panic: reflect: call of reflect.Value.Set on zero Value [recovered] panic: reflect: call of reflect.Value.Set on zero Value 在嵌套字段中被调用时变成r,但是我该如何解决呢?

我的<invalid Value>当然不是r,不可寻址且不可设置。我可以用它制作一个valid,但是我不知道如何设置新的reflect.New以便修改原始结构的字段。无论我做什么,我的函数都不会使用这种方法修改带有嵌套名称的字段。

我尝试过的另一种解决方案是添加一个         价值体现 到我的reflect.Value结构中,并修改ProtoField,使其附加一个analyze,其中reflect.ValueOf(s).Field(i)是顶层结构s,而interface{}是它的第一个字段。然后,每当遇到嵌套字段时,我都会调用i,但是问题是由于类型不兼容,我无法调用r := reflect.ValueOf(field.Value)

非常感谢您的帮助或见解。

1 个答案:

答案 0 :(得分:0)

问题解决了。 ThunderCat在他的评论中是对的:诀窍是使用FieldByIndex。我之前没有注意到该方法的签名,我认为它接受整数作为参数,但实际上它需要整数的 slice 。然后,很容易修改我的analyze函数,该函数以递归方式遍历该结构,现在还随其构造一个索引切片。现在我可以r := reflect.ValueOf(&result).Elem().FieldByIndex(field.Idx)了,我在笑。

经验教训在这里:如果要使用反射设置嵌套struct字段的值,请不要按名称调用它们;按索引称呼他们。