53. Protocol buffer 的Go使用

文章目录

  • 一、介绍
  • 二、安装
  • 三、protoc3语法
    • 1、 protoc3 与 protoc2区别
    • 2、proto3生成go代码
      • Message
      • 内嵌Message
      • 字段
        • 单一标量字段
        • 单一message字段
        • 可重复字段slice
        • map字段
        • 枚举

一、介绍

ProtobufGoogle旗下的一款平台无关,语言无关,可扩展的序列化结构数据格式。所以很适合用做数据存储和作为不同应用,不同语言之间相互通信的数据交换格式,只要实现相同的协议格式,即同一proto文件被编译成不同的语言版本,加入到各自的工程中去,这样不同语言就可以解析其他语言通过Protobuf序列化的数据。目前官网提供了C++,Python,JAVA,GO等语言的支持。

二、安装

  1. Mac上安装Protoc3
  2. Windows安装Protoc3
  3. 安装protoc-gen-go
    protoc-gen-go是生成Go代码的protocolbuffers编译器。可以理解为一个编译器插件,配合protoc来使用。在命令行执行如下命令即可完成安装:
go get -u github.com/golang/protobuf/protoc-gen-go@latest

网上资料推荐的基本都是这个命令,但目前该模块已被弃用,继续使用该命令将出现错误,提示该库已经被弃用,让我们使用go get -u google.golang.org/protobuf/

三、protoc3语法

1、 protoc3 与 protoc2区别

proto3proto2的基础上去掉了一些复杂的语法和特性,更强调约定而弱化语法。主要几点区别如下:

  1. proto文件第一行非空白非注释行,必须指定版本,syntax = "proto3";如果不指定,则默认是proto2
  2. 字段规则移除了 required,并把 optional改名为 singular,省略不写时,默认就是singular
  3. repeated字段默认采用 packed 编码,在 proto2 中,需要明确使用[packed=true] 来为字段指定比较紧凑的 packed 编码方式。
  4. 语言增加 Go、Ruby、JavaNano 支持,即在proto2时并不支持go语言。
  5. 移除了default 选项,在proto2中,可以使用default选项为某一字段指定默认值。在 proto3 中,字段的默认值只能根据字段类型由系统决定。也就是说,默认值全部是约定好的,而不再提供指定默认值的语法。在字段被设置为默认值的时候,该字段不会被序列化。这样可以节省空间,提高效率。
    但这样就无法区分某字段是根本没赋值,还是赋值了默认值。 所以一般需要避免将默认值作为任何行为的触发方式。例如
enum AudienceDisplayTypeEnum {NoValue = 0; // (占位符)说明端上没有传入此参数,请勿使用CurrentCount = 1; // 展示当前直播间内人数AccumulativeCount = 2; // 展示直播间累计人数SettingEntranceClosed = 99; // 端上拿到则不展示此选项,相当于配置项是否出现的开关
}

此例子是控制直播间展示在线人数还是看播人次的开关,开关仅两个取值:truefalse,但这里并没有使用bool类型,因为bool型默认值是false,即使前端没有给我们传该值,我们也会拿到false值,从而可能当成是前端传过来的值,切换开关,因此使用枚举。使用枚举后,不使用01表示开关的打开与关闭,因为0是枚举的默认值,也不应该作为控制行为的值,因此有业务含义的从序号为1的字段开始。
6. 枚举类型的第一个字段必须为 0,因为枚举会把第一个字段作为默认值
7. 增加了JSON映射特性,如

message XXXRequest {string  name = 1; int64 begin_time = 2 (go.tag = "json:\"beginTime\"");int64 end_time = 3;int32 page_no = 4;int32 page_size = 5;
}

2、proto3生成go代码

Go Proto Buffer代码生成官网文档地址

如果一个.proto文件中有包声明,生成的源代码将会使用它来作为Go的包名,如果.proto的包名中有. ,在Go包名中会将.转换为_。举例来说proto包名example.high_score将会生成Go包名example_high_score

.proto文件中可以使用option go_package指令来覆盖上面默认生成Go包名的规则。比如说包含如下指令的一个.proto文件

package example.high_score;
option go_package = "/test";

生成的Go源代码的包名是test

如果一个.proto文件中不包含package声明,生成的源代码将会使用.proto文件的文件名作为Go包名,.会被首先转换为_。举例来说一个名为high.score.proto不包含package声明的文件将会生成文件high.score.pb.go,他的Go包名是high_score

Message

一个简单的message声明:

message Foo {}

protocol buffer编译器将会生成一个名为Foo的结构体,var A *Foo为实现了proto.Message接口的Foo类型的指针,因为Foo实现了proto.Message接口中ProtoMessage()方法,生成的XXX.pb.go文件将包含如下代码片段,注意看注释哦

type Foo struct {
}// 重置proto为默认值
func (m *Foo) Reset()         { *m = Foo{} }// String 返回proto的字符串表示
func (m *Foo) String() string { return proto.CompactTextString(m) }// ProtoMessage作为一个tag 确保其他人不会意外的实现
// proto.Message 接口.
func (*Foo) ProtoMessage()    {}

内嵌Message

一个message可以声明在其他message的内部。比如:

message Foo {message Bar {}
}

这种情况,编译器会生成两个结构体:FooFoo_Bar

字段

编译器会为每个在message中定义的字段生成一个Go结构体的字段,字段的确切性质取决于它的类型以及它是singular,repeated,map还是oneof字段。

注意生成的Go结构体的字段将始终使用驼峰命名,即在.proto文件中消息字段用的是小写加下划线(工作中基本都是这种形式),生成的Go代码会是大驼峰命名。大小写转换的原理如下:

  • 首字母会大写,如果message中字段的第一个字符是_,它将被替换为X
  • 如果内部下划线后跟小写字母,则删除下划线,并将后面跟随的字母大写。
    因此,proto字段foo_bar_bazGo中变成FooBarBaz _my_field_name变为XMyFieldName
单一标量字段

对于包级别字段定义:

int32 id = 1;

编译器将生成一个带有名为Idint32字段和一个访问器方法GetId()的结构,该方法返回结构体中Id字段的零值(如果字段未设置(数值型零值为0,字符串为空字符串))。

单一message字段

给出如下消息类型

message Bar {}

对于一个有Bar类型字段的消息:

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

编译器将会生成一个Go结构体

type Baz struct {Foo *Bar
}

消息类型的字段可以设置为nil,这意味着该字段未设置。

编译器还生成一个func(m *Baz)GetFoo() *Bar辅助函数。这让不在中间检查nil值进行链式调用成为可能,因为该方法中会进行相关字段的nil判断。

可重复字段slice

每个重复的字段在Go中的结构中生成一个T类型的slice,其中T是字段的元素类型。对于带有重复字段的消息:

message Baz {repeated Bar foo = 1;
}

编译器会生成如下结构体:

type Baz struct {Foo  []*Bar
}

同样,对于字段定义repeated bytes foo = 1; 编译器将会生成一个带有类型为[][]byte, 名为Foo的字段的Go结构体。对于可重复的枚举repeated MyEnum bar = 2;,编译器会生成带有类型为[]MyEnum, 名为Bar的字段的Go结构体。

map字段

每个映射字段会在Go的结构体中生成一个map[TKey]TValue类型的字段,其中TKey是字段的键类型,TValue是字段的值类型。对于下面这个消息定义:

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

编译器生成Go结构体

type Baz struct {Foo map[string]*Bar
}
枚举

给出如下枚举

message SearchRequest {enum Corpus {UNIVERSAL = 0;WEB = 1;IMAGES = 2;LOCAL = 3;NEWS = 4;PRODUCTS = 5;VIDEO = 6;}Corpus corpus = 1;
}

编译器将会生成一个枚举类型和一系列该类型的常量。

对于消息中的枚举(像上面那样),类型名字以消息名开头

type SearchRequest_Corpus int32

对于包级别的枚举:

// .proto
enum Foo {DEFAULT_BAR = 0;BAR_BELLS = 1;BAR_B_CUE = 2;
}

Go中的类型不会对proto中的枚举名称进行修改:

type Foo int32

此类型具有String()方法,该方法返回给定值的名称。

Enum()方法使用给定值初始化新分配的内存并返回相应的指针:

func (Foo) Enum() *Foo

编译器为枚举中的每个值生成一个常量。对于消息中的枚举,常量以消息的名称开头:

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

对于包级别的枚举,常量以枚举名称开头:

const (Foo_DEFAULT_BAR Foo = 0Foo_BAR_BELLS   Foo = 1Foo_BAR_B_CUE   Foo = 2
)

protobuf编译器还生成从整数值到字符串名称的映射以及从名称到值的映射:

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/209059.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AWS KeyPair密钥格式转换PPK<>PEM

概述说明 PEM&#xff08;Privacy Enhanced Mail&#xff09;和PPK&#xff08;Putty Private Key&#xff09;都是与加密和安全相关的文件格式&#xff0c;通常用于存储私钥信息。它们在不同的上下文中使用&#xff0c;并且与不同的软件和协议相关联。 PEM&#xff08;Priva…

【kubernetes】k3s集群搭建(正在更新……)

文章目录 一、k3s简介二、快速搭建1.控制平面2.镜像加速 Pod容器集1.创建和管理pod Deployment(部署)与ReplicaSet(副本集)滚动更新 Service命名空间YAML语法管理对象常用命令缩写YAML规范 声明式配置对象标签选择器 容器运行时接口(CRI)与镜像导入导出容器运行时接口(CRI) 金丝…

基于POSIX标准的Linux进程间通信

文章目录 1 管道&#xff08;匿名管道&#xff09;1.1 管道抽象1.2 接口——pipe1.3 管道的特征1.4 管道的四种情况1.5 匿名管道用例 2 命名管道2.1 创建一个命名管道——mkfifo2.2 关闭一个管道文件——unlink2.3 管道和命名管道的补充2.4 命名管道用例 3 共享内存3.1 原理3.2…

案例二:SQL Server数据库的备份和还原

1、备份类型。 在 SQL Server 中提供了三种常用的备份类型&#xff0c;分别是完整备份&#xff0e;差异备份和事务日志备份。 完整备份&#xff1a; 完整备份包括对整个数据库、部分事务日志、数据库结构和文件结构的备份。完整备份代表的是备份完成时刻的数据库。 完整备份是…

【Hydro】Python绘制降雨径流双Y轴成果图

目录 说明源代码说明 双y轴图像具有单y轴图像没有的对比效果,通常会用来绘制降雨径流成果图,在MATLAB中有plotyy函数可以实现,Python的实现方式没有MATLAB那样方便,不过实现效果却也不见得差。 Python中的matplotlib通常使用twinx来生成双Y轴,下图便是使用matplotlib绘制…

8、操作符重载

友元 可以通过friend关键字&#xff0c;把一个全局函数、另一个类的成员函数或者另一个类整体&#xff0c;声明为授权类的友元友元拥有访问授权类任何非公有成员的特权友元声明可以出现在授权类的公有、私有或者保护等任何区域且不受访问控制限定符的约束友元不是成员&#xf…

elment-table设置el-table-column的label里面的文字换行居中显示

效果图如下&#xff1a; 直接上代码&#xff1a; <el-table class"ut-mt-2" row-key"company" default-expand-all:data"stateQuery.data" style"width: 100%":tree-props"{ children: departList, hasChildren: hasChildre…

Si24R03—低功耗 SOC 芯片(集成RISC-V内核+2.4GHz无线收发器)

Si24R03是一款高度集成的低功耗SOC芯片&#xff0c;其集成了基于RISC-V核的低功耗MCU和工作在2.4GHz ISM频段的无线收发器模块。 MCU模块具有低功耗、Low Pin Count、宽电压工作范围&#xff0c;集成了13/14/15/16位精度的ADC、LVD、UART、SPI、I2C、TIMER、WUP、IWDG、RTC等丰…

PandoraFMS 监控软件 任意文件上传漏洞复现

0x01 产品简介 Pandora FMS 是用于监控计算机网络的软件。 Pandora FMS 允许以可视化方式监控来自不同操作系统、服务器、应用程序和硬件系统(例如防火墙、代理、数据库、Web 服务器或路由器)的多个参数的状态和性能。 0x02 漏洞概述 PandoraFMS upload_head_image.php 接…

.bat文件设置窗口标题、窗口大小、字体及背景颜色?

设置cmd窗口的标题 1、打开.bat文件编辑 2、输入命令&#xff1a; title&#xff08;窗口标题&#xff09; 比如&#xff1a;title计算机 3、保存 4、双击运行.bat文件 &#xff0c;窗口标题改变成功 改变窗口大小 1、打开.bat文件编辑 2、输入命令&#xff1a; mode co…

Java中的Stream是什么?

在Java中&#xff0c;Stream是一种用于处理集合&#xff08;Collections&#xff09;元素的抽象序列。它允许你在集合上进行不同类型的操作&#xff0c;比如筛选、映射、过滤和归约等。Stream API引入了一种更函数式的编程风格&#xff0c;能够简化集合处理的过程。 Stream并不…

NLP项目实战01之电影评论分类

介绍&#xff1a; 欢迎来到本篇文章&#xff01;在这里&#xff0c;我们将探讨一个常见而重要的自然语言处理任务——文本分类。具体而言&#xff0c;我们将关注情感分析任务&#xff0c;即通过分析电影评论的情感来判断评论是正面的、负面的。 展示&#xff1a; 训练展示如下…

【基于LicheePi-4A的 人脸识别系统软件设计】

参考:https://www.xrvm.cn/community/post/detail?spm=a2cl5.27438731.0.0.31d40dck0dckmg&id=4253195599836418048 1.前言 原先计划做基于深度学习的炸药抓取和智能填装方法研究,但是后来发现板卡不支持pyrealsense2等多个依赖包。因此改变策略,做一款基于LicheePi…

Android Studio的笔记--三元表达式、布尔运算符、与() 或(||) 非(!)

[TOC](三元表达式、布尔运算符、与(&&) 或(||) 非(!)) 表达式 int x 1; int y 2;x < y 结果 true x > y 结果 false x < y 结果 false x > y 结果 true x y 结果 false x ! y 结果 true 布尔运算符 boolean boolean a true; boolean b false; 与…

【Python】列表乘积的计算时间

概述 使用以下三种模式测量了计算列表乘积所需的时间。 使用 for 语句传递list使用math模块使用numpy 下面是实际运行的代码。 import timestart time.time() A [1] * 100000000 ans 1 for a in A:ans * a print("list loop:", time.time() - start)import m…

前端面试提问(4)

1、手撕防抖与节流、树与对象的转换、递归调用&#xff0c;链表头插法 1.1、防抖 防抖函数用于延迟执行某个函数&#xff0c;直到过了一定的间隔时间&#xff08;例如等待用户停止输入&#xff09;后再执行。 即后一次点击事件发生时间距离一次点击事件至少间隔一定时间。 …

笙默考试管理系统-MyExamTest----codemirror(49)

笙默考试管理系统-MyExamTest----codemirror&#xff08;49&#xff09; 目录 笙默考试管理系统-MyExamTest----codemirror&#xff08;49&#xff09; 一、 笙默考试管理系统-MyExamTest----codemirror 二、 笙默考试管理系统-MyExamTest----codemirror 三、 笙默考试…

有哪些已经上线的vue商城项目?

前言 下面是一些商城的项目&#xff0c;需要练手的同学可以挑选一些来练&#xff0c;废话少说&#xff0c;让我们直接开始正题~~ 1、newbee-mall-vue3-app 是一个基于 Vue 3 和 TypeScript 的电商前端项目&#xff0c;它是 newbee-mall 项目的升级版。该项目包含了商品列表、…

内网环境下 - 安装linux命令、搭建docker以及安装镜像

一 内网环境安装docker 先在外网环境下载好docker二进制文件docker二进制文件下载&#xff0c;要下载对应硬件平台的文件&#xff0c;否则不兼容 如下载linux平台下的文件&#xff0c;直接访问这里即可linux版本docker二进制文件 这里下载docker-24.0.5.tgz 将下载好的文件…