protoBuf-go学习笔记

小咪咪 2023-03-13 06:44 310阅读 0赞

protoBuf-go学习笔记

    • protoBuf官方简介
    • 下载protoBuf编译器
    • 安装go专属plugin
    • 编译proto到go代码
    • proto包名
    • syntax声明
    • 导入包
    • 定义message
    • 定义字段
    • 定义服务
    • golang使用proto

protoBuf官方简介

  1. protocol buffers 是一种语言无关、平台无关、可扩展的序列化结构数据的方法
  2. 它可用于(数据)通信协议、数据存储等。
  3. Protocol Buffers 是一种灵活,高效,自动化机制的结构数据序列化方法
  4. 可类比 XML,但是比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单。
  5. 你可以定义数据的结构,然后使用特殊生成的源代码
  6. 轻松的在各种数据流中使用各种语言进行编写和读取结构数据。
  7. 你甚至可以更新数据结构,而不破坏由旧数据结构编译的已部署程序。

protobuf通过定义包含类型结构序列化信息的文件(.proto文件),来编译生成不同语言平台的高效序列化程序代码

下载protoBuf编译器

根据不同系统下载不同protoc编译器,在windows下下载windows后缀的
protoc-3.12.0-rc-1-winxxx.zip
解压后得到的目录中,bin目录中的protoc.exe就是编译protoc代码命令

  1. Mode LastWriteTime Length Name
  2. ---- ------------- ------ ----
  3. d----- 2020/5/5 1:24 bin
  4. d----- 2020/5/5 1:24 include
  5. -a---- 2020/5/5 1:24 724 readme.txt

把protoc.exe复制到GOPATH/bin目录下

安装go专属plugin

protobuf编译器有支持golang需要安装protoc-gen-go这个go插件
通过下载源码编译后,把编译出的exe重命名为protoc-gen-go.exe放到GOPATH/bin下
github.com/golang/protobuf

  1. cd protoc-gen-go
  2. go build main.go

编译proto到go代码

在确保有将GOPATH/bin加入环境变量后,即可在任意目录使用protoc命令

  1. protoc --go_out=. --proto_path=. *.proto

其中,go_out指定编译的go代码输出路径,proto_path指定查找proto文件所在的根目录,最后一个参数是要编译的proto文件名
最终旧生成了代码文件xxx.pb.go

proto包名

如果编译出现警告

  1. Missing 'go_package' option in "test.proto"

这是因为默认.proto文件中的包声明生成源代码时作为Go的包名,包名中的. 在Go包名中会转换为_。
比如proto包名a.b将会变为Go包名a_b,所以一般通过option go_package指令来指定Go包名
比如如下代码指定了go包名为a.b(不管是否定义了proto包名)

  1. option go_package = "a.b";

syntax声明

一般在proto文件开头使用syntax声明proto版本,默认是proto2
比如

  1. syntax = "proto3";

导入包

通过import语句导入proto包,比如

  1. import "google/protobuf/struct.proto"

定义message

protobuf中使用关键字message定义结构,并且结构中可以嵌套定义结构,比如

  1. message A {}
  2. message B {
  3. message C {
  4. }
  5. }

内嵌类型最终会编译为以外部类型名称_名称作为类型名称的结构体,比如此处,生成的结构体有3个,分别是

  1. type A struct {...}
  2. type B struct {...}
  3. type B_C struct {...}

定义字段

基本定义语法如下,其中type是类型,name是字段名称,num是数据编号
当反序列化时,会把对应数据编号对应的数据填充到对应字段
对于type,如果是message类型,在编译为语言代码时会被转化为对应的指针类型

  1. type name = num
  • 基本类型

    1. message A {
    2. string name = 1;
    3. }
  • message类型

    1. message B {
    2. string name = 1;
    3. }
    4. message A {
    5. B b = 1;
    6. }
  • map

    1. message A {
    2. map<string,int> pic = 1;
    3. }
  • 枚举
    枚举类型会被编译为整型的替代类型,枚举值会变为const变量,以类型名_枚举量名作为名称
    与message类似,枚举也可以嵌套在类型中,最终会编译为以外部类型名称_枚举名称作为类型名称
    比较独特的,枚举枚举中枚举量的数值就是他们编译后代码中常量的初始化数值,第一个枚举量的数据编号必须是0

    1. message A{
    2. enum Color{
    3. RED = 0;
    4. BLACK = 1;
    5. }
    6. Color c = 1;
    7. }
    8. enum Day{
    9. ONE = 0;
    10. TWO = 1;
    11. }
  • repeated类型(数组)
    通过在类型前加上关键字repeated代表其为数组类型,该字段序列化可能出现0次或多次,比如

    1. message B{}
    2. message A{
    3. repeated B bs= 1;
    4. }

    最终生成

    1. type B struct {...}
    2. type A struct {
    3. ...
    4. Bs []*B ...
    5. }

定义服务

proto支持通过service与rpc关键字分别定义rpc服务和rpc方法,proto默认不会生成rpc代码,需要结合对应的rpc插件(grpc、twirp等)编译才会生成
比如如下代码,定义了一个service,提供一个search的rpc调用方法,接收一个Request类型的参数,返回Response类型的结果

  1. message Request{}
  2. message Response{}
  3. service Search{
  4. rpc search(Request) returns(Response);
  5. }

golang使用proto

  • 依赖

    1. google.golang.org/protobuf/
  • 导入包

    1. google.golang.org/protobuf/proto
  • proto.Marshal(interface{} obj) 方法将对象序列化为字节数组
  • proto.Unmarshal([]byte bs, interface{} obj)方法将字节数组反序列化为对象

    1. //A is message
    2. a := A{}
    3. bis, _ := proto.Marshal(&a)
    4. fmt.Printf("%v\n", bis)
    5. var r A
    6. proto.Unmarshal(bis, &r)
    7. fmt.Printf("%v\n", r)

    更多文章,请搜索公众号歪歪梯Club
    更多资料,请搜索公众号编程宝可梦

发表评论

表情:
评论列表 (有 0 条评论,310人围观)

还没有评论,来说两句吧...

相关阅读

    相关 学习笔记

    \ajax: 1、概念:异步的JavaScript 和 xml 1.1异步和同步:客户端和服务器端相互通信的基础上 \客户端必须等待服务器端的响应。在等待的期间客户