如何从Protobuf生成不含额外隐藏字段的Golang结构体?
问题描述
参考以下消息定义:
message Moo { uint64 generation = 1; string title = 2; bytes payload = 3; repeated string flags = 4; }
protoc生成的type Moo struct中包含state、sizeCache、unknownFields等额外字段,我还需要生成一个不含这些额外字段的结构体,例如:
type MooLight struct { Generation uint64 Title string Payload []byte Flags []string }
(结构体标签有无对我无关紧要,为清晰起见此处已省略)。
我知道可以编写代码读取生成的moo.pb.go文件,基于var File_moo_proto protoreflect.FileDescriptor生成这类“轻量”结构体,但更希望通过protoc直接实现。请问有什么建议?我曾查看Go protoc插件,但代码量庞大。
可行解决方案
1. 编写极简自定义protoc Go插件
不用照搬官方插件的复杂逻辑,基于google.golang.org/protobuf的protoreflect和protoc-gen-go/plugin包,可以写一个几十行的极简插件,只负责生成轻量结构体:
核心思路:
- 接收protoc传递的CodeGeneratorRequest
- 遍历所有消息类型
- 对每个消息,生成对应的
XXXLight结构体,只保留业务字段
示例核心代码片段:
package main import ( "google.golang.org/protobuf/compiler/protogen" "google.golang.org/protobuf/types/descriptorpb" ) func main() { protogen.Options{}.Run(func(gen *protogen.Plugin) error { for _, f := range gen.Files { if !f.Generate { continue } generateLightStructs(gen, f) } return nil }) } func generateLightStructs(gen *protogen.Plugin, file *protogen.File) { g := gen.NewGeneratedFile(file.GeneratedFilenamePrefix+"_light.pb.go", file.GoImportPath) g.P("// Code generated by protoc-gen-go-light. DO NOT EDIT.") g.P() g.P("package ", file.GoPackageName) g.P() for _, msg := range file.Messages { structName := msg.GoName + "Light" g.P("type ", structName, " struct {") for _, field := range msg.Fields { fieldType := field.Desc.Kind().String() if field.Desc.IsRepeated() { fieldType = "[]" + fieldType } if field.Desc.Kind() == descriptorpb.FieldDescriptorProto_TYPE_BYTES { fieldType = "[]byte" } g.P("\t", field.GoName, " ", fieldType) } g.P("}") g.P() } }
编译这个插件后,用protoc调用:
protoc --go_out=. --go_opt=paths=source_relative --plugin=protoc-gen-go-light=./protoc-gen-go-light moo.proto
2. 使用第三方轻量生成插件
已有成熟的第三方插件可以直接生成无额外字段的结构体,比如:
protoc-gen-go-strict: 生成仅包含业务字段的结构体,支持自定义命名规则protoc-gen-go-minimal: 专注生成极简结构体,去掉所有protoc附加字段
使用时只需安装对应插件,然后在protoc命令中添加对应参数即可,无需自己写代码。
3. 结合Descriptor和Go模板生成
如果不想写插件,可以用protoc输出descriptor文件,再结合Go模板生成轻量结构体:
- 生成descriptor文件:
protoc --descriptor_set_out=moo.desc --include_imports moo.proto # 转成JSON格式更易处理 protoc --descriptor_set_out=moo.desc --include_imports moo.proto && protoc --decode_raw < moo.desc > moo.json
- 编写Go模板文件(比如
light_struct.tmpl):
package {{.Package}} {{range .Messages}} type {{.Name}}Light struct { {{range .Fields}} {{.GoName}} {{.Type}} {{end}} } {{end}}
- 编写简单的Go程序读取descriptor,解析出字段名称、类型等信息,渲染模板生成代码。
这种方式无需涉及protoc插件的复杂逻辑,适合快速实现需求。
内容的提问来源于stack exchange,提问作者JayEye
相关产品推荐
相关产品推荐

