最近有给小功能需求,找了一圈都没找到怎么实现,所以请教一下各位大哥,需求是这样的
动态的序列化protobuf, 比如通过proto中消息的名字来序列号proto
我的实现思路如下:
首先 通过protoc生成对应的*.pb.go文件,然后编译另外一个工程,另一个工程的main函数通过加载*.pb.go文件,然后通过反射来序列化。
因为pb.go文件会在init方法中注册类型,所以可以通过proto.MessageType(name)方法取到pb.go文件中的Type信息
然后通过reflect.New()方法可以取到结构体的指针,再通过各种field方法设置值。
目前我卡在,通过reflect.New方法怎么都一直为nil,我没办法将其指向某个存在的结构体的指针,翻遍了reflect包的test中也没看到类似用法,希望各位大神能帮帮忙!!
贴一下代码中的一小段:其中的的gameProto.WineConfig为pb中定义的消息,这个代码能跑,但是替换成
v := reflect.ValueOf(cfg).Elem()就会报错
for i := _TITLE_LINE_NUM; i <= rowLast; i++ {
cfg1 := &gameProto.WineConfig{}
fmt.Println("1111", reflect.TypeOf(cfg1), cfg1)
cfg := reflect.New(rtype).Elem().Interface()
// 现在关键点在于reflect.New()不能真的创建出一个结构体指针,只能创建出一个nil值
//因为指针的零值就是nil,所以需要用到结构体的零值 reflect.Zero(v) 可以创建结构体的零值
v := reflect.ValueOf(cfg1).Elem()
fmt.Println("v=", v, "cfg=", cfg, "rtype=", rtype)
for j := 0; j <= colLast; j++ {
rtype, needGen, name := getColumnType(xs.ReadStr(0, j, nil))
if !needGen {
continue
}
val := xs.ReadStr(i, j, nil)
switch rtype {
case "ti":
strings.Split(val, ";")
case "ts":
case "int32":
iv, _ := strconv.Atoi(val)
fieldV := v.FieldByName(name)
fieldV.Set(reflect.ValueOf(proto.Int32(int32(iv))))
case "string":
fieldV := v.FieldByName(name)
fieldV.Set(reflect.ValueOf(proto.String(val)))
}
}
sb.EncodeMessage(cfg.(proto.Message))
}
#1