protoBuf-go学习笔记

protoBuf官方简介

protocol buffers 是一种语言无关、平台无关、可扩展的序列化结构数据的方法
它可用于(数据)通信协议、数据存储等。

Protocol Buffers 是一种灵活,高效,自动化机制的结构数据序列化方法
可类比 XML,但是比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单。

你可以定义数据的结构,然后使用特殊生成的源代码
轻松的在各种数据流中使用各种语言进行编写和读取结构数据。
你甚至可以更新数据结构,而不破坏由旧数据结构编译的已部署程序。

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

下载protoBuf编译器

根据不同系统下载不同protoc编译器,在windows下下载windows后缀的
protoc-3.12.0-rc-1-winxxx.zip

解压后得到的目录中,bin目录中的protoc.exe就是编译protoc代码命令

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----         2020/5/5      1:24                bin
d-----         2020/5/5      1:24                include
-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

cd protoc-gen-go
go build main.go

编译proto到go代码

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

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

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

proto包名

如果编译出现警告

Missing 'go_package' option in "test.proto"

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

option go_package = "a.b";

syntax声明

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

syntax = "proto3";

导入包

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

import "google/protobuf/struct.proto"

定义message

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

message A {}
message B {
	message C {
	}
}

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

type A struct {...}
type B struct {...}
type B_C struct {...}

定义字段

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

type  name = num
  • 基本类型
    message A {
    	string name = 1;
    }
    
  • message类型
    message B {
    	string name = 1;
    }
    message A {
    	B b = 1;
    }
    
  • map
    message A {
    	map<string,int> pic = 1;
    }
    
  • 枚举
    枚举类型会被编译为整型的替代类型,枚举值会变为const变量,以类型名_枚举量名作为名称
    与message类似,枚举也可以嵌套在类型中,最终会编译为以外部类型名称_枚举名称作为类型名称
    比较独特的,枚举枚举中枚举量的数值就是他们编译后代码中常量的初始化数值,第一个枚举量的数据编号必须是0
    message A{
      enum Color{
        RED = 0;
        BLACK = 1;
      }
      Color c = 1;
    }
    enum Day{
        ONE = 0;
        TWO = 1;
    }
    
  • repeated类型(数组)
    通过在类型前加上关键字repeated代表其为数组类型,该字段序列化可能出现0次或多次,比如
    message B{}
    message A{
      repeated B bs= 1;
    }
    
    最终生成
    type B struct {...}
    type A struct {
    	...
    	Bs []*B ...
    }
    

定义服务

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

message Request{}
message Response{}
service Search{
	rpc search(Request) returns(Response);
}

golang使用proto

  • 依赖
    google.golang.org/protobuf/
    
  • 导入包
    google.golang.org/protobuf/proto
    
  • proto.Marshal(interface{} obj) 方法将对象序列化为字节数组
  • proto.Unmarshal([]byte bs, interface{} obj)方法将字节数组反序列化为对象
    //A is message
    
    a := A{}
    bis, _ := proto.Marshal(&a)
    
    fmt.Printf("%v\n", bis)
    
    var r A
    proto.Unmarshal(bis, &r)
    
    fmt.Printf("%v\n", r)
    

欢迎找歪歪梯聊骚

原创文章 53 获赞 12 访问量 9051

猜你喜欢

转载自blog.csdn.net/weixin_44627989/article/details/106079336
今日推荐