protobuf学习笔记(一):生成一个比较综合的message

本文介绍了protobuf在golang中的应用,包括其基本概念、数据格式、语法结构,以及如何定义和使用复杂的数据类型如枚举、any和时间戳,以及如何通过protoc生成go代码。
摘要由CSDN通过智能技术生成

一年前学过对应的知识,终究是太潦草了,这几天网上学习了一下,重新写一下笔记。这里是protobuf和golang的结合

一、protobuf

protobuf实际上是一种类似json和gob之类的数据格式,也是grpc的御用格式吧(有自己的优势,这里我就不写了),其有着自己的定义方式,结合对应的指令可以实现转化成对应语言的操作。

二、写一个复杂一点的例子

先把我写的例子,整体粘过来,然后再做具体的分析

syntax="proto3";//顶格声明protobuf版本,默认是protobuf2
// 注意一下语句后面要加";",否则不识别
package user;//定义一下protobuf的包名,包名影响什么后续会写
import "role.proto";//这里编辑器报错不用管,应该是插件不能识别的问题
import "parent.proto";
import "google/protobuf/any.proto";//引入any类型
import "google/protobuf/timestamp.proto";//引入时间戳类型
/*
import public "some path"
这个public关键词用于控制这个包的依赖是否可以传递,例子如下

a.proto:
import "b.proto"
import public "c.proto"

index.proto:
import "a.proto"
那么这个index文件当中除了能使用a文件中定义的变量,还能使用c文件当中的遍历,但是b文件就不能使用

*/
option go_package="../grpc;grpc";//规定生成文件的输出文件,同时规定对应文件package的名称
//这里指定的 out_path 并不是绝对路径,只是相对路径或者说只是路径的一部分,和 protoc 的 --go_out 拼接后才是完整的路径。所以我的侧率就是不写go_out

// 这边我们写一个User结构体
//结构体的名称我们采取的是官网上的格式,注意和golang默认格式区分
// 具体的protobuf基础类型和对应语言之间对应表,参见https://protobuf.dev/programming-guides/proto3/#specifying-field-rules

message TestUser{
    // 保留字段和保留数字,这个用法我不是很懂,我看的资料显示如下
    /*
    如果一个字段不再需要,如果删除或者注释掉,则其他人在修改时会再次使用这些字段编号,
    那么旧的引用程序就可能出现一些错误,所以使用保留字段,保留已弃用的字段编号或字段名 
    我个人觉得这应该涉及到可拓展性的问题(难道更改的时候不会去重新生成对应的文件吗)
    */
    reserved "hh";
    reserved 99 to 100;
    string name=1;
    uint64 id=2;
    optional float height=3;//默认字段都是必填,optional表示可选
    double money=4;
    bool merried=5;
    role.Role role=6;//这个就是role包引入的枚举类型,枚举定义在message内部就是独占枚举
    google.protobuf.Any other_msg=7;//any类型
    oneof child_name{
        string son_name=8;
        string daughter_name=9;//暂时看起来不同于枚举,oneof控制的事不同字段只能选一个
    }
    repeated string hobby=10;//可重复字段,应该会生成一个切片

    //内嵌字段,注意tag只是在同一个message内不能重复,内嵌的字段不算
    // 内嵌的字段是能单独拿出来用的,比如在另一个字段中,可以使用TestUser.GameCharacter
    // 注意这里的行为只是定义,要使用可以如下这样写
    //repeated GameCharacter game_character =100;
    message GameCharacter{
        string name=1;
        uint64 character_id=2;
    }

    // 创建一个map
    map<string,parent.Parent> parents=11;

    // 创建一个时间戳类型
    google.protobuf.Timestamp birthday=12;
}

1、前两个声明

syntax="proto3";//顶格声明protobuf版本,默认是protobuf2

第一个是版本声明 

package user;//定义一下protobuf的包名

包名的声明,后面引入外部文件的时候会用大

2、四个import 

前两个import引入了本报之外的其他两个文件,这两个应用的文件内容如下:

//role.proto
syntax="proto3";
package role;
option go_package="../grpc;grpc";
enum Role{
    NORMAL_USER=0;
    VIP_USER=1;
    BOSS=3;
};
//parent.proto
syntax="proto3";
package parent;
option go_package="../grpc;grpc";
message Parent{
    string name=1;
    uint32 age=2;
}

这两个引用在下面的TestUser之中的role字段和map中被使用,主要是我用来测试外部引入的。

后面两个import则是引入了官网定义的两个类型Any和Timestamp,也在下面的TestUser结构中使用

import "google/protobuf/any.proto";//引入any类型
import "google/protobuf/timestamp.proto";//引入时间戳类型

3、import public

引入前面可以加入public关键词,具体用法可以看这段

import public "some path"
这个public关键词用于控制这个包的依赖是否可以传递,例子如下

//a.proto:
import "b.proto"
import public "c.proto"

//index.proto:
import "a.proto"
那么这个index文件当中除了能使用a文件中定义的变量,还能使用c文件当中的遍历,但是b文件就不能使用

4、go_package

这个控制转化后的go文件的生成地址和生成go文件的package名,比如我这里的写法就是

option go_package="../grpc;grpc";//规定生成文件的输出文件,同时规定对应文件package的名称

 生成的文件放到上级的grpc文件夹中,package是grpc,两个之间以“;”这格符号隔开,需要注意这个生成文件的存放路径需要和protoc指令中的“--go_out=“值相拼接,我为了不出错,都是只写go_package,"--go_out"的内容我是不写的

5、具体的TestUser字段

这里需要注意一下大小写的问题,message类似于结构体,他的名称是开头双大写,而其里面的字段则是小写,用“_”连接。

一下基础的类型比如string等等,可以查看对应的protobuf基础类型和对应语言之间对应表,参见https://protobuf.dev/programming-guides/proto3/#specifying-field-rules。

这里还展示了其他操作

optional:可选关键字

enum:这里是外部引入的role.Role类型

any:google.protobuf.Any,也是外部引入的

oneof:字段二选一,不同于枚举,这里的例子就是孩子的名字要么是男孩名字,要么是女孩名字

repeated:多次关键词,比如例子里的hobby字段,实际上会形成一个数组/切片(实际上字段名称写成hobbies比较好)

map类型:这里我们生成的是一个<string,parent.Parent>的键值对,其中parent.Parent是外部引入

时间戳类型:google.protobuf.Timestamp也是一个外部引入

6、内嵌message和enum

朋友们应该注意到了,我在TestUser之中还声明了一个GameCharacter(注意只是申明,要在TestUser使用还要显式挂载),也能声明一个枚举,有需要的时候可以在外部使用

三、生成一下protobuf

首先要安装一下protoc-gen-go生成工具来使用protoc指令

go install google.golang.org/protobuf/cmd/protoc-gen-go@latest

控制台使用如下指令查看是否安装成功

protoc --version

其次在项目中引入相关包

go get -u google.golang.org/protobuf

注意区分这次学习只生成protobuf,并不生成grpc的客户端和服务端,也就是这次只会生成对应的结构体

进入protobuf原始文件所在文件夹,控制台使用如下指令生成:

protoc --go_out=.  *.proto

protoc指令其实有--proto_path和--go_out两个参数,第一个参数告知protobuf文件所在文件夹,但是由于路径我这边怎么写都不对,所以我直接进入了protobuf所在文件夹,这样就不写这个参数了。

--go_out=.这个写法就是让文件中go_package选项决定输出文件何在。

*.proto表示处理所有文件,当然你也可以指定具体文件名,中间用空号隔开。

最后就会在grpc文件夹之中生成parent.pb.go/user.pd.go/role.pd.go三个文件,具体文件的里的实现,可以自己去看,有些写法还是很有意思的。

加下来会加上grpc包,除了protobuf文件之外,还会有对应的客户端

  • 22
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值