duanbi9202 2018-09-17 13:44
浏览 265

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

I'm trying to create a protobuf structure out of a

type FlatMessage map[string][]byte

and I'm struggling with setting values of nested fields.

I have an

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

method to transform flat message into structured protobuf.

I also have a helper function called analyze which takes a struct of type pb.Message and returns a map[int]*ProtoField where:

type ProtoField struct {
    Name  string
    Type  reflect.Type
}

i.e. analyze traverses pb.Message recursively and gathers all the information I need about it. So far so good.

Now when I go key by key through my FlatMessage, the key is an encoded field number of a respective protobuf field, and I can set it using reflection, like this:

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

but that works only when the field.Name in question does not refer to a nested field, i.e., setting OldV1Id works fine, but attempting to set Profile.Id or, say, Destination.Address.TypeOfNumber, results in:

panic: reflect: call of reflect.Value.Set on zero Value [recovered]
    panic: reflect: call of reflect.Value.Set on zero Value

I understand that this is due to the fact that my r becomes <invalid Value> when called on a field which is a nested one, but how can I work around it?

My r is of course not valid, not addressable, and not settable. I can make a reflect.New out of it, but I can't figure out how to set that new reflect.Value in such a way that the field of my original structures becomes modified. No matter what I do the my function doesn't modify fields with nested names with this approach.

Another solution I tried is adding a Value reflect.Value to my ProtoField structure, and modifying analyze so that it appends a reflect.ValueOf(s).Field(i) where s is the top-level struct interface{} and i is its ith field. Then whenever I encounter a field that is a nested one, I call r := reflect.ValueOf(field.Value), but then the problem is I'm unable to call r.Set(scalarValue) because of incompatible types.

Any help or insight is much appreciated.

  • 写回答

1条回答 默认 最新

  • douou8954 2018-09-17 19:53
    关注

    Problem solved. ThunderCat was right in his comment: the trick is to use FieldByIndex. I didn't notice the signature of that method before, I thought it accepts an integer as an argument, but in fact it takes a slice of integers. It was then easy to modify my analyze function that traverses the structure recursively and now also constructs a slice of indexes as it goes. Now I can just r := reflect.ValueOf(&result).Elem().FieldByIndex(field.Idx) and I'm laughing.

    Lesson learned here: if you want to set values of nested struct fields using reflection, don't call them by name; call them by index.

    评论

报告相同问题?

悬赏问题

  • ¥28 微信小程序开发页面布局没问题,真机调试的时候页面布局就乱了
  • ¥15 python的qt5界面
  • ¥15 无线电能传输系统MATLAB仿真问题
  • ¥50 如何用脚本实现输入法的热键设置
  • ¥20 我想使用一些网络协议或者部分协议也行,主要想实现类似于traceroute的一定步长内的路由拓扑功能
  • ¥30 深度学习,前后端连接
  • ¥15 孟德尔随机化结果不一致
  • ¥15 apm2.8飞控罗盘bad health,加速度计校准失败
  • ¥15 求解O-S方程的特征值问题给出边界层布拉休斯平行流的中性曲线
  • ¥15 谁有desed数据集呀