本文描述了protocol buffers使用.proto文件生成pb.go文件的过程

编译器

  编译器需要插件来编译环境,使用如下方式安装插件:go get github.com/golang/protobuf/protoc-gen-go

  使用.proto生成的文件相比输入文件有如下两处变更:

    • 生成文件的文件名为:输入文件的扩展名.pb.go,如使用player.proto生成的文件名为player.pb.go
    • 生成文件的路径为--go_out指定的文件

  当执行如下命令时:

protoc --proto_path=src --go_out=build/gen src/foo.proto src/bar/baz.proto

  编译器会读取src/foo.proto src/bar/baz.proto,并分别生成build/gen/foo.pb.go and build/gen/bar/baz.pb.go。编译器会自动生成build/gen/bar目录,但不会生成build或build/gen目录。

 如果.proto文件包含包定义,则生成的代码会使用.proto的package,与go的package处理类似,会将package名字中的"."转换为"_"。如proto package名为example.high_score,对应生成的代码的package name为example_high_score。

  使用go_package选项可以替换默认条件下.proto生成的package name。如下生成的go package为“hs".

package example.high_score;
option go_package = "hs";

  如果.proto文件中没有包含package声明,则生成的代码会使用文件名(处理方式类似go package name)

消息

下面是一个简单的message

message Foo {}

  protocol buffer 编译器会生成一个struct,名为Foo。A *Foo实现了该接口的方法。下述成员会出现在所有message生成的go代码中

type Foo struct {
} // Reset sets the proto's state to default values.
func (m *Foo) Reset() { *m = Foo{} } // String returns a string representation of the proto.
func (m *Foo) String() string { return proto.CompactTextString(m) } // ProtoMessage acts as a tag to make sure no one accidentally implements the
// proto.Message interface.
func (*Foo) ProtoMessage() {}

内嵌类型

如下内嵌场景下会生成2个独立的struct,Foo和Foo_Bar

message Foo {
message Bar {
}
}

Well_known 类型

  protocol buffer的预定义消息集合,称为well_known types(WKTs)。这些类型在与其他服务交互时比较好用。如Struct消息表示了任意的C风格的struct。

  为WTKs预生成的go代码作为Go protobuf library的一部分发布。如给出一个message  

import "google/protobuf/struct.proto"
import "google/protobuf/timestamp.proto" message NamedStruct {
string name = 1;
google.protobuf.Struct definition = 2;
google.protobuf.Timestamp last_modified = 3;
}

  生成的Go代码如下:  

import google_protobuf "github.com/golang/protobuf/ptypes/struct"
import google_protobuf1 "github.com/golang/protobuf/ptypes/timestamp" ... type NamedStruct struct {
Name string
Definition *google_protobuf.Struct
LastModified *google_protobuf1.Timestamp
}

字段 

  生成的go字段名称遵循驼峰命名法,规则如下:

    • 首字母大写,如果首字符是下划线,则使用大写X替换该下划线
    • 如果字符内部的下划线后跟着小写的字母,则移除该下划线,并将原来下划线后面的字母大写

  如foo_bar_baz变为FooBarBaz,_my_field_name_2变为XMyFieldName_2

  Singular Scalar Fields (proto3)

int32 foo = 1;

  编译器会生成一个包含名为int32字段,名为Foo的struct,以及一个名为GetFoo()的方法,该方法会返回Foo中定义的int32的值,或默认值(如果设置初始值)

   Singular Message Fields

message Bar {}
message Baz {
  Bar foo = 1;
}

  针对message Baz,编译器会生成如下struct,以及一个func (m *Baz)GetFoo() *Bar的函数。

type Baz struct {
Foo *Bar //结构体使用指针
}

  Repeated Fields   

message Baz {
repeated Bar foo = 1;
}

  生成如下struct。类似地,如果字段定义为 repeated bytes foo = 1,编译器会生成名为Foo,含[][]byte字段的Go struct;字段定义为 repeated MyEnum bar = 2,则会生成名为Bar,包含[]MyEnum字段的struct

type Baz struct {
Foo []*Bar //相比不带repead的,多了"[]"
}

  Map Fields  

message Bar {}

message Baz {
map<string, Bar> foo = 1;
}

  编译器生成如下struct

type Baz struct{
Foo map[string]*Bar //map中的结构体也是指针表达方式
}

  Oneof Fields

  针对oneof字段,protobuf编译器会生成接口类型 isMessageName_MyField。此外oneof中的每个singular字段会生成struct,isMessageName_MyField接口。如下oneof:  

package account;
message Profile {
oneof avatar {
string image_url = 1;
bytes image_data = 2;
}
}

  编译器会生成struct:  

type Profile struct {
// Types that are valid to be assigned to Avatar:
// *Profile_ImageUrl
// *Profile_ImageData
Avatar isProfile_Avatar `protobuf_oneof:"avatar"`
} type Profile_ImageUrl struct {
ImageUrl string
}
type Profile_ImageData struct {
ImageData []byte
}

  *Profile_ImageUrl 和*Profile_ImageData都使用一个空的isProfile_Avatar()实现了isProfile_Avatar 编译器同时会生成func (m *Profile) GetImageUrl() string 和func (m *Profile) GetImageData() []byte

  如下展示了如何设置字段:  

p1 := &account.Profile{
Avatar: &account.Profile_ImageUrl{"http://example.com/image.png"},
} // imageData is []byte
imageData := getImageData()
p2 := &account.Profile{
Avatar: &account.Profile_ImageData{imageData},
}

  可以使用如下来处理不同的message类型

switch x := m.Avatar.(type) {
case *account.Profile_ImageUrl:
// Load profile image based on URL
// using x.ImageUrl
case *account.Profile_ImageData:
// Load profile image based on bytes
// using x.ImageData
case nil:
// The field is not set.
default:
return fmt.Errorf("Profile.Avatar has unexpected type %T", x)
}

  Enumerations  

message SearchRequest {
enum Corpus {
UNIVERSAL = ;
WEB = ;
IMAGES = ;
LOCAL = ;
NEWS = ;
PRODUCTS = ;
VIDEO = ;
}
Corpus corpus = ;
...
}

  protocol buffer会生成一个类型以及一系列该类型表示的常量。在message内部的enums,type的名称会以message名称开头:

type SearchRequest_Corpus int32
const (
SearchRequest_UNIVERSAL SearchRequest_Corpus = 0
SearchRequest_WEB SearchRequest_Corpus = 1
SearchRequest_IMAGES SearchRequest_Corpus = 2
SearchRequest_LOCAL SearchRequest_Corpus = 3
SearchRequest_NEWS SearchRequest_Corpus = 4
SearchRequest_PRODUCTS SearchRequest_Corpus = 5
SearchRequest_VIDEO SearchRequest_Corpus = 6
)

  package级别的enum

enum Foo {
DEFAULT_BAR = ;
BAR_BELLS = ;
BAR_B_CUE = ;
}

Go类型以原来的enum,该类型还有一个String()方法来返回给定值的名字,Enum()方法初始化并分配给定值的内存,返回相应的指针。

type Foo int32
func (Foo) Enum() *Foo

  protocol buffer编译器也会整数到字符串名称以及名称到数值的对应关系  

var Foo_name = map[int32]string{
: "DEFAULT_BAR",
: "BAR_BELLS",
: "BAR_B_CUE",
}
var Foo_value = map[string]int32{
"DEFAULT_BAR": ,
"BAR_BELLS": ,
"BAR_B_CUE": ,
}

  .proto允许多enum的数值相同。由于多名称对应一个数值,逆向对应关系则是数值与.proto文件中出现的第一个名称相对应(一个对应关系)。

  service

  Go代码生成器默认不会为services生成代码。如果使能了gRPC插件,则可以支持个RPC代码的生成。

参见:GO Generated Code

protocol buffers生成go代码原理的更多相关文章

  1. Google Protocol Buffers 快速入门(带生成C#源码的方法)

    Google Protocol Buffers是google出品的一个协议生成工具,特点就是跨平台,效率高,速度快,对我们自己的程序定义和使用私有协议很有帮助. Protocol Buffers入门: ...

  2. Protocol Buffers工作原理

    这里记录一下学习与使用Protocol Buffer的笔记,优点缺点如何使用这里不再叙述,重点关注与理解Protocol Buffers的工作原理,其大概实现. 我们经常使用Protocol Buff ...

  3. protocol buffers的编码原理

    protocol buffers使用二进制传输格式传递消息,因此相比于xml,json来说要轻便很多. 示例:假设定义了一个Message message Test1 { required int32 ...

  4. Google Protocol Buffer 的使用和原理

    Google Protocol Buffer 的使用和原理 Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,很适合做数据存储或 RPC 数据交换格式.它 ...

  5. Google Protocol Buffers介绍

    简要介绍和总结protobuf的一些关键点,从我之前做的ppt里摘录而成,希望能节省protobuf初学者的入门时间.这是一个简单的Demo. Protobuf 简介 Protobuf全称Google ...

  6. 转Google Protocol Buffer 的使用和原理

    Google Protocol Buffer 的使用和原理 Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,很适合做数据存储或 RPC 数据交换格式.它 ...

  7. Protocol Buffers介绍及例子

    Protocol Buffers介绍及例子 Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化.它很适合做数据存储或数据交换格式.可用于通讯协 ...

  8. 在Android中使用Protocol Buffers(下篇)

    本文来自网易云社区. FlatBuffers编码数组 编码数组的过程如下: 先执行 startVector(),这个方法会记录数组的长度,处理元素的对齐,准备足够的空间,并设置nested,用于指示记 ...

  9. Protocol Buffers官方文档(开发指南)

    本文是对官方文档的翻译,然后截取了一篇非常优秀的文章片段来帮助理解,本人英文水平有限,基本都是直译,如果有不理解的地方请参考英文官方文档,参考的文章链接在文章末尾 protocol buffers简介 ...

随机推荐

  1. 基于MOD13A1的锡林郭勒草原近13年植被覆盖变化 分析

    内蒙古师范大学地理科学学院 内蒙古师范大学遥感与地理信息系统重点实验室 摘要:本研究以内蒙古锡林郭勒草原为研究区,基于MOD13A1遥感数据,经过遥感预处理,得到研究区2001-2013年共13年夏季 ...

  2. hdu 5000 共存问题->背包

    http://acm.hdu.edu.cn/showproblem.php?pid=5000 每只羊有n个属性 下面n个数字表示每个属性的值范围为[ 0, T[i] ] 对于羊圈里的a羊和b羊,若a羊 ...

  3. Vuejs——(5)v-on

    版权声明:出处http://blog.csdn.net/qq20004604   目录(?)[+]   资料来于官方文档: http://cn.vuejs.org/guide/events.html ...

  4. 【笔记】virtualbox+arch+kde5安装流水账

    正常安装就是RTFD就行了,不行辅助这几个链接也行: 我先把整个脚本[1]放这里: loadkeys us parted mkfs.ext4 /dev/sda1mkfs.ext4 /dev/sda3 ...

  5. 创建TFS备份计划失败,错误提示:TF400997

    问题描述 在一个TFS 2018 + SQL Server 2017的环境中,从TFS控制台中配置备份计划时,系统提示错误TF400997,需要授予数据库服务账户sqlservice@domain.c ...

  6. Django报错:ConnectionAbortedError: [WinError 10053] 你的主机中的软件中止了一个已建立的连接。

    ajax请求时加上 async : false, $.ajax({ url:"{% url 'article:article_post' %}", {#一定不要写成小写了,坑了好久 ...

  7. Struts2-057/CVE-2018-11776两个版本RCE漏洞分析(含EXP)

    0x01 前言 2018年8月22日,Apache Strust2发布最新安全公告,Apache Struts2存在远程代码执行的高危漏洞(S2-057/CVE-2018-11776),该漏洞由Sem ...

  8. HttpWebRequest 模拟浏览器访问网站

    最近抓网页时报错: 要么返回 The remote server returned an error: (442)要么返回: 非法访问,您的行为已被WAF系统记录! 想了想,就当是人家加了抓网页的东西 ...

  9. .net core An assembly specified in the application dependencied mainfest<****.json>was not found解决办法

    最近在开发项目中,遇到了一个问题.在本机开发中部署到本机iis上或者本机控制台都没有问题,运行正常.当发布部署到服务器(windowsServer)中的时候一直运行不起来,用控制台也运行不起来,直接报 ...

  10. div水平垂直居中方法及优缺点

    代码: <div class="father"> <div class="son"> </div></div> ...