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
}
ie 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, ie, 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.
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.