您可以简单地使用经常重复的字段定义一条新消息,并将其用作其他消息中的字段类型:
message Metadata {
uint64 id = 1;
google.protobuf.Timestamp createdAt = 2;
google.protobuf.Timestamp updatedAt = 3;
}
message League {
Metadata metadata = 1;
string name = 2;
//...
}
在 Go 中,您将把 Metadata 字段初始化为普通结构(包选择器将取决于您实际从 protobuffers 生成 Go 类型的方式):
func newLeague() *grpcgen.League {
return &grpcgen.League{
Metadata: &grpcgen.Metadata{
Id: 1000,
CreatedAt: ptypes.TimestampProto(time.Now()),
UpdatedAt: ptypes.TimestampProto(time.Now()),
}
Name: "foo",
//...
}
}
编辑:
你认为这会减慢编码/解码过程
我们可以运行以下基准测试:
package foo
import (
"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/ptypes"
"foo/grpcgen"
"testing"
)
var withmeta = &grpcgen.LeagueWithMeta{
Metadata: &grpcgen.Metadata{
Id: 1000,
CreatedAt: ptypes.TimestampNow(),
UpdatedAt: ptypes.TimestampNow(),
},
Name: "foo",
}
var nometa = &grpcgen.LeagueNoMeta{
Id: 1000,
CreatedAt: ptypes.TimestampNow(),
UpdatedAt: ptypes.TimestampNow(),
Name: "foo",
}
func BenchmarkEncProto(b *testing.B) {
b.Run("encode with meta", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
b, _ := proto.Marshal(withmeta)
if b == nil {
panic("not marshaled")
}
}
})
b.Run("encode without meta", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
b, _ := proto.Marshal(nometa)
if b == nil {
panic("not marshaled")
}
}
})
}
$ go test -bench=. ./proto_benchmark_test.go -benchtime=10s
goos: darwin
goarch: amd64
cpu: Intel(R) Core(TM) i7-7660U CPU @ 2.50GHz
BenchmarkEncProto/encode_with_meta-4 13124650 948.8 ns/op 96 B/op 4 allocs/op
BenchmarkEncProto/encode_without_meta-4 25832161 417.0 ns/op 64 B/op 2 allocs/op
PASS
ok command-line-arguments 24.629s
不将字段包装在Metadata 消息中具有更好的性能,这并不奇怪。实际上,这不会以明显的方式影响您的程序。