什么是Protobuf?如何使用Protobuf?

Protocol Buffers (protobuf) 介绍

官方文档:https://protobuf.dev/programming-guides/proto3/

Protocol Buffers(简称 protobuf)是由 Google 开发的一种语言中立、平台中立、可扩展的序列化数据格式。它用于结构化数据的序列化和反序列化,常用于远程过程调用(RPC)、数据存储等场景。protobuf 提供了一种高效的方式来定义和传输结构化数据。

主要特点

1. 高效

protobuf 使用二进制格式进行序列化,比 JSON 或 XML 等文本格式更紧凑,占用更少的空间,传输和解析速度更快。

2. 跨语言支持

protobuf 支持多种编程语言,包括但不限于 C++、Java、Python、Go 和 C#。这种语言中立性使得不同语言编写的系统之间可以轻松地进行数据交换。

3. 易于定义

使用 .proto 文件定义数据结构,语法简单直观,可以方便地进行版本管理和扩展。

4. 向后兼容和向前兼容

protobuf 的设计考虑到了版本兼容性,可以轻松地进行数据结构的扩展而不影响现有系统。

Protocol Buffers 基本类型和默认值

在 Protocol Buffers (protobuf) 中,可以定义多种基本数据类型。这些类型可以用于定义消息字段的类型,并且每种类型都有其默认值。当消息中某个字段没有被赋值时,序列化后的消息会使用该字段的默认值。

Protocol Buffers 类型说明默认值Go 数据类型Python 数据类型
int32有符号 32 位整数0int32int
int64有符号 64 位整数0int64int
uint32无符号 32 位整数0uint32int
uint64无符号 64 位整数0uint64int
sint32有符号 32 位整数(采用 ZigZag 编码)0int32int
sint64有符号 64 位整数(采用 ZigZag 编码)0int64int
fixed32固定长度的无符号 32 位整数0uint32int
fixed64固定长度的无符号 64 位整数0uint64int
sfixed32固定长度的有符号 32 位整数0int32int
sfixed64固定长度的有符号 64 位整数0int64int
float32 位浮点数0.0float32float
double64 位浮点数0.0float64float
bool布尔值falseboolbool
string字符串(UTF-8 或 7-bit ASCII 编码)""stringstr
bytes任意字节序列b''[]bytebytes

Protocol Buffers中的Option关键字

在 Protocol Buffers (protobuf) 中,option 关键字用于指定和定制 .proto 文件的各种配置和行为。

主要包括:

  • 文件级别的 option:用于指定语法版本、包名以及生成代码时的特定选项。
  • 消息级别的 option:用于配置特定消息的生成代码的包名和外部类名。
  • 字段级别的 option:用于为特定字段定义自定义行为,如标记字段为废弃或设置默认值(在 proto2 中)。

常见的option示例:

Option描述示例用法
syntax指定 .proto 文件的语法版本。syntax = "proto3";
package定义生成代码的包命名空间。package example;
go_package指定生成的 Go 代码的包名。option go_package = "examplepb";
java_package指定生成的 Java 代码的包名。option java_package = "com.example.protos";
java_outer_classname指定生成的 Java 代码的外部类名。option java_outer_classname = "ExampleProto";
自定义字段选项允许为特定消息字段定义自定义行为。int32 id = 1 [deprecated = true];
optional int32 id = 1 [default = 0]; (proto2)

Protocol Buffers中的Message嵌套

嵌套Message的语法

在 protobuf 的消息定义中,可以在一个消息中定义另一个消息类型。语法如下:

message OuterMessage {
    // 其他字段...
    message InnerMessage {
        // 内部消息类型的字段定义
    }

    // 可以在这里使用 InnerMessage 类型的字段
    InnerMessage inner_message_field = 1;
}

示例说明

假设我们要定义一个包含订单信息的消息,并且每个订单包含多个商品。可以使用嵌套消息来表示这种关系:

message Order {
    int32 order_id = 1;
    string customer_name = 2;

    message Product {
        string product_id = 1;
        string product_name = 2;
        float price = 3;
    }

    repeated Product products = 3;
}

在这个示例中:

  • Order 是外部消息类型,包含了 order_idcustomer_nameproducts 字段。
  • Product 是嵌套的消息类型,它包含了表示产品的字段:product_idproduct_nameprice
  • repeated Product products 表示 Order 消息中可以包含多个 Product 类型的数据,使用 repeated 关键字表示这是一个数组或者列表。

嵌套Message的实例化

以上面的为例,利用 命令生成代码文件后,如何实例化嵌套对象Product呢?

引入生成的代码文件后,实例化如下所示

product := proto.Order_Product{
		ProductId:   1,
		ProductName: "phone",
		Price:       1000,
	}

嵌套Message的优点

  • 组织性和清晰性:可以更清晰地表示复杂的数据结构和关系。
  • 模块化:可以将相关的消息类型放在一起,提高代码的模块化程度。
  • 封装性:内部消息类型可以更好地隐藏实现细节,只暴露必要的接口。

Protocol Buffers中的枚举类型(enum)

在 Protocol Buffers (protobuf) 中,枚举类型用于定义一组命名的常量集合。它们提供了一种有效管理常量值的方式,使得消息结构更具可读性和可维护性。

定义枚举类型

在 protobuf 中,定义枚举类型的语法如下:

message YourMessage {
    Status status = 1;
}

enum Status {protobuf 
    ACTIVE = 0;
    ARCHIVED = 1;
}

示例说明

在 protobuf 中,定义枚举枚举的示例如下:

message Strudent {
  string name = 1;
  int32 age = 2;
  Gender gender = 3;
}

enum Gender {
  MALE = 0;
  FEMALE = 1;
}

如何使用

利用命令生成对应的代码文件后,使用方法如下:

可以利用proto.Gender_MALE或者proto.Gender_FEMALE,不推荐使用Gender: 0Gender: 1

student := proto.Strudent{
		Age:    18,
		Name:   "张三",
		Gender: proto.Gender_MALE, // 或 proto.Gender_FEMALE, 不推荐Gender: 0/1,
	}

Protocol Buffers中的Map

在 Protocol Buffers (protobuf) 中,可以使用 map 类型来定义键值对集合。这种类型在描述键值对关系时非常有用,可以在消息中表示映射结构,如字典或哈希表。使用 map 类型可以方便地存储和检索键值对数据,提高了消息结构的灵活性和表达能力。

定义 map 类型

在 protobuf 中,定义 map 类型的语法如下:

组件描述
key_type表示映射中键的类型,可以是基本数据类型(例如 int32string)或枚举类型。
value_type表示映射中值的类型,可以是任何支持的数据类型(例如 int32string、消息类型)。
map_field消息中存储键值对映射的字段名。
field_number在序列化和反序列化过程中用来唯一标识字段的编号。
message YourMessage {
    map<key_type, value_type> map_field = field_number;
}

示例说明

在 protobuf 中,定义枚举Map的示例如下:

message Strudent {
  string name = 1;
  int32 age = 2;
  map<string, int32> grade = 3;
}

如何使用

利用命令生成对应的代码文件后,使用方法如下:

student := proto.Strudent{
		Age:   18,
		Name:  "张三",
		Grade: map[string]int32{
			"Chinese": 100,
			"English": 100,
		},
	}

Protocol Buffers中的Timestamp

在 Protocol Buffers(protobuf)中,Timestamp 是一个特定的消息类型,用来表示时间戳信息。它通常与其他消息一起使用,用于记录事件发生的具体时间。

示例说明

在 protobuf 中,定义枚举Timestamp 的示例如下:

import "google/protobuf/timestamp.proto";

message Strudent {
  string name = 1;
  int32 age = 2;
  google.protobuf.Timestamp current = 3;
}

如何使用

利用命令生成对应的代码文件后,使用方法如下:

import (
	"xxxx/proto"
	"google.golang.org/protobuf/types/known/timestamppb"
	"time"
)

func main() {
	student := proto.Strudent{
		Age:  18,
		Name: "张三",
		Current: timestamppb.New(time.Now()),
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值