【go语言】protobuf 和 grpc

一、protobuf 的基本类型和默认值

1.1 基本类型

一个标量消息字段可以包含有一个如下的类型------该表格展示了定义于 .proto 文件中的类型,以及与之对应的、在自动生成的访问类中定义的类型:

  • 对于所有的情况,设定值会执行类型检查以确保此值是有效的
  • 64位或者无符号32位整形在解码时被表示为 long,但是在设置时可以使用 int 型值设定,在所有的情况下,值必须符合其设置其类型的要求

1.2 默认值

当一个消息被解析的时候,如果被编码的信息部包含一个特定的 singular 元素,被解析的对象所对应的域被设置为一个默认值,对于不同类型指定如下:

  • 对于 strings,默认为一个空 string
  • 对于 bytes,默认为一个空的 bytes
  • 对于 bools,默认为 false
  • 对于数值类型,默认为 0
  • 对于枚举,默认为第一个定义的枚举值,必须为 0
  • 对于消息类型,域没有被设置,确切的消息是根据语言确定的
  • 对于可重复域的默认值是空

二、option go_package 的作用

option go_package.proto 文件中指定生成的 Go 代码的包路径。它告诉 protoc 编译器生成的 Go 文件应该放在什么位置,并且应该使用哪个 Go 包名。这对 Go 开发者来说是非常重要的,因为它确保了生成的 Go 代码能够正确地与其他 Go 代码进行集成。

2.1 为什么需要 option go_package

  1. 确定包路径:Go 代码会根据这个选项来决定生成的 Go 文件放置的路径和包名,确保代码结构符合 Go 项目的标准结构。

  2. 避免冲突 :如果多个 .proto 文件生成的 Go 代码没有正确指定 go_package,可能会发生包名冲突或无法正确导入其他生成的文件。

  3. 与 Go 代码整合go_package 还帮助 Go 工具链(比如 go getgo mod)正确识别和导入生成的代码。

假设你有一个 .proto 文件 helloworld.proto,你希望生成的 Go 代码放在 github.com/yourusername/yourrepo/helloworld 包中。你可以在 .proto 文件中添加 go_package 选项:

Go 复制代码
syntax = "proto3";

package helloworld;

// 使用 go_package 指定 Go 包路径
option go_package = "github.com/yourusername/yourrepo/helloworld";

// 定义消息和服务
message HelloRequest {
  string name = 1;
}

message HelloResponse {
  string message = 1;
}

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloResponse);
}

2.2 option go_package的作用

  • 指定 Go 包路径option go_package = "github.com/yourusername/yourrepo/helloworld"; 指定了生成的 Go 文件会位于 github.com/yourusername/yourrepo/helloworld 包下。这样,你在其他地方导入这些 Go 文件时就可以使用该路径。

  • 帮助 Go 工具链 :当使用 protoc 命令生成 Go 代码时,option go_package 会确保 Go 文件放到正确的位置,并且在 import 时能够正确解析路径。

2.3 使用 protoc 命令时的影响

生成 go 代码时,protoc 会根据 go_package 选项来决定生成的 go 文件的路径。里融入,使用以下命令生成 go 代码:

Go 复制代码
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative helloworld.proto

生成的 Go 代码将会根据 go_package 中指定的路径生成。例如,Go 文件 helloworld.pb.go 将被放置在 github.com/yourusername/yourrepo/helloworld 包中。

三、proto 文件同步时的坑

在进行编写 proto 文件的时候,我们需要将编号和变量一一对应,不能出现在不同目录下的同一个proto 文件出现不对等的情况,否则会出现一些错误。

四、proto 文件中 import 另一个文件

在 proto 文件中,使用 import 语句可以导入其他 .proto 文件,这样就能使用其他文件中定义的消息类型,服务等。

例如,假设有两个 proto 文件,file1.protofile2.proto,你想在 file2.proto 中使用 file1.proto 中定义的消息类型。

Go 复制代码
syntax = "proto3";

package example;

message Person {
  string name = 1;
  int32 id = 2;
}
Go 复制代码
syntax = "proto3";

package example;

import "file1.proto";  // 导入 file1.proto

message AddressBook {
  repeated Person people = 1;  // 使用 file1.proto 中的 Person 类型
}

需要注意:

  • import 语句可以是相对路径或绝对路径,具体取决于你的文件结构和编译时的配置。
  • 如果你导入的 .proto 文件在不同的目录中,你需要在 import 语句中指定相应的路径。

五、嵌套的 message 对象

proto 文件中,嵌套的 message 对象 是指在一个 message 类型内部定义另一个 message 类型。嵌套的 message 可以像其他普通的 message 一样被使用。

这种方式通常用于组织复杂的结构,方便保持数据结构的层级关系。

Go 复制代码
syntax = "proto3";

package example;

// 嵌套的 Address 类型
message Person {
  string name = 1;
  int32 id = 2;

  // 嵌套的 Address 类型
  message Address {
    string street = 1;
    string city = 2;
    string state = 3;
    string zip_code = 4;
  }

  Address address = 3;  // 使用嵌套的 Address 类型
}
  1. 嵌套 message :在 Person 类型内部定义了一个 Address 类型。这样,Address 就成为了 Person 的一部分。AddressPerson 类型的一个字段,它包含 streetcitystatezip_code 字段。

  2. 使用嵌套的 Address :在 Person 的字段中,我们可以直接使用嵌套的 Address 类型,就像普通的 message 一样。

  • 层级数据结构 :适用于那些具有层次结构的数据模型。例如,表示人和地址时,地址是人数据的一部分,因此它可以嵌套在 Person 中。
  • 封装数据 :当数据是逻辑上紧密关联的,嵌套的 message 可以帮助将它们封装在一起,减少不必要的重复定义。
相关推荐
小姚也要变强13 分钟前
sort排序 计数排序 map set C++ 蓝桥杯
开发语言·c++·算法·蓝桥杯
Lx35235 分钟前
Pandas高级数据处理:数据流处理
后端·python·pandas
美味小鱼39 分钟前
Rust 的基本类型有哪些,他们存在堆上还是栈上,是否可以COPY?
开发语言·后端·rust
AI量化投资实验室40 分钟前
celery策略回测任务运行及金融量化数据增量更新|年化18.8%,回撤8%的组合策略(python代码)
开发语言·python·金融
Dr.勿忘1 小时前
C#面试常考随笔12:游戏开发中常用的设计模式【C#面试题(中级篇)补充】
开发语言·unity·设计模式·面试·c#·游戏引擎
孔瑾熙1 小时前
Elixir语言的网络编程
开发语言·后端·golang
DARLING Zero two♡1 小时前
C++效率掌握之STL库:string函数全解
开发语言·c++·stl·string
关关钧2 小时前
【R语言】环境空间
开发语言·r语言
YGGP2 小时前
【Go语言圣经】第七节:接口
golang
小袁拒绝摆烂3 小时前
mybatis辅助配置
java·开发语言·mybatis