相较于文本编码的 JSON
- 速度快(序列化和反序列化)
- 数据小(二进制数据流更加紧凑)
- 数据类型丰富(enum,map...)
- 可读性差
数据类型
Protobuf 类型 | 描述 | Go 对应类型 |
---|---|---|
int32 |
有符号 32 位整数,采用可变长度编码,适合较小的整数 | int32 |
int64 |
有符号 64 位整数,采用可变长度编码 | int64 |
uint32 |
无符号 32 位整数,采用可变长度编码 | uint32 |
uint64 |
无符号 64 位整数,采用可变长度编码 | uint64 |
sint32 |
有符号 32 位整数,采用 ZigZag 编码,适合负数较多的情况 | int32 |
sint64 |
有符号 64 位整数,采用 ZigZag 编码 | int64 |
fixed32 |
无符号 32 位整数,固定 4 字节编码,对于大整数比 uint32 更高效 |
uint32 |
fixed64 |
无符号 64 位整数,固定 8 字节编码 | uint64 |
sfixed32 |
有符号 32 位整数,固定 4 字节编码 | int32 |
sfixed64 |
有符号 64 位整数,固定 8 字节编码 | int64 |
float |
单精度 32 位浮点数 | float32 |
double |
双精度 64 位浮点数 | float64 |
bool |
布尔值,取值为 true 或 false |
bool |
string |
包含 UTF - 8 编码或 7 位 ASCII 文本的字符串,长度不能超过 2^32 | string |
bytes |
任意的字节序列,长度不能超过 2^32 | []byte |
message |
自定义的数据结构,由多个字段组成,可以嵌套定义 | struct |
enum |
用于定义一组命名的常量值 | Go 枚举实现 |
repeated |
在字段前加上 repeated 关键字表示该字段是一个数组 |
Go 数组 |
map<KeyType, ValueType> |
从 proto3 开始支持的映射类型,用于表示键值对 | map |
-
枚举类型,有另一篇文章可供参考:Protobuf 枚举类型的实现
-
数组(Repeated)示例:
message Person { repeated string hobbies = 5; }
-
映射(Map)示例:
message Person { map<string, string> contacts = 6; }
这里
contacts
是一个键为字符串、值也为字符串的映射。
基本流程
- 定义数据结构(.proto 文件)
- 使用编译器生成目标编程语言代码
-
在程序中引入生成的代码
-
Protobuf 编译器: protoc,作用是生成目标语言的数据定义代码
生成的代码
需要到 GitHub 下载。 -
Protobuf 运行时,作用是序列化和反序列化的基础库
Lang Repo C++ https://github.com/protocolbuffers/protobuf/blob/main/src Java https://github.com/protocolbuffers/protobuf/blob/main/java Python https://github.com/protocolbuffers/protobuf/blob/main/python Golang https://github.com/protocolbuffers/protobuf-go
示例
-
proto 文件
syntax = "proto3"; package example; message Person { enum Gender { UNKNOWN = 0; MALE = 1; FEMALE = 2; } string name = 1; int32 age = 2; Gender gender = 3; }
-
编译:
$ protoc --go_out=. --go_opt=Mexample.proto=./generated example.proto $ find . . ./example.proto ./generated ./generated/example.pb.go
-
调用 proto 生成的 Go 代码
package main import ( "fmt" "log" pb "example/generated" // 导入生成的包 "google.golang.org/protobuf/proto" ) func main() { // 创建一个 Person 实例 person := &pb.Person{ Name: "Alice", Age: 30, Gender: pb.Person_FEMALE, } // 序列化 data, err := proto.Marshal(person) if err != nil { log.Fatalf("Failed to marshal: %v", err) } // 反序列化 newPerson := &pb.Person{} err = proto.Unmarshal(data, newPerson) if err != nil { log.Fatalf("Failed to unmarshal: %v", err) } fmt.Printf("Deserialized person: %+v\n", newPerson) }
$ go mod init example $ go mod tidy $ go build -o main.exe . $ ./main.exe Deserialized person: name:"Alice" age:30 gender:FEMALE