为了账号安全,请及时绑定邮箱和手机立即绑定

如何不对每个原型结构重复相同的字段?

如何不对每个原型结构重复相同的字段?

Go
慕姐4208626 2022-08-24 17:01:38
我第一次使用protobuf .proto文件。我有许多模型具有相同的字段:message Player {  uint64 id = 1;  google.protobuf.Timestamp createdAt = 2;  google.protobuf.Timestamp updatedAt = 3;  string firstname = 4;  string lastname = 5;  //...}message Team {  uint64 id = 1;  google.protobuf.Timestamp createdAt = 2;  google.protobuf.Timestamp updatedAt = 3;  string name = 4;  //...}message League {  uint64 id = 1;  google.protobuf.Timestamp createdAt = 2;  google.protobuf.Timestamp updatedAt = 3;  string name = 4;  //...}...和许多其他...如您所见,我在每个结构中都重复了相同的字段。在这种情况下,DRY(不要重复自己)的最佳实践是什么?我正在使用Golang。我可以像在 Go 语言中一样嵌入它们吗?
查看完整描述

1 回答

?
12345678_0001

TA贡献1802条经验 获得超5个赞

您只需使用经常重复的字段定义一个新消息,并将其用作其他消息中的字段类型:


message Metadata {

  uint64 id = 1;

  google.protobuf.Timestamp createdAt = 2;

  google.protobuf.Timestamp updatedAt = 3;

}


message League {

  Metadata metadata = 1;

  string name = 2;

  //...

}

在 Go 中,您将该字段初始化为普通结构(包选择器将取决于您如何从 protobuffers 实际生成 Go 类型):Metadata


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


查看完整回答
反对 回复 2022-08-24
  • 1 回答
  • 0 关注
  • 71 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信