Protobuf - Go 数据序列化
Protocol Buffers (Protobuf) 是 Google 开发的二进制序列化格式,广泛用于 gRPC 和数据存储。掌握 Protobuf 是开发高性能分布式系统的基础。
定义消息
📝 .proto 文件
// user.proto
syntax = "proto3";
package user;
option go_package = "github.com/example/proto";
// 枚举类型
enum UserRole {
USER_ROLE_UNSPECIFIED = 0;
USER_ROLE_ADMIN = 1;
USER_ROLE_MEMBER = 2;
USER_ROLE_GUEST = 3;
}
// 消息定义
message User {
int64 id = 1;
string name = 2;
string email = 3;
int32 age = 4;
UserRole role = 5;
bool active = 6;
repeated string tags = 7; // 列表
Profile profile = 8; // 嵌套消息
}
message Profile {
string bio = 1;
string avatar_url = 2;
map<string, string> social_links = 3; // Map
}
// Oneof: 互斥字段
message Contact {
oneof contact_info {
string email = 1;
string phone = 2;
}
}
生成代码
📝 编译 Proto 文件
# 安装 protoc 编译器
# macOS
brew install protobuf
# Ubuntu/Debian
apt-get install protobuf-compiler
# 安装 Go 插件
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
# 生成 Go 代码
protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
user.proto
# 生成文件:
# - user.pb.go (消息定义)
# - user_grpc.pb.go (gRPC 服务)
使用消息
📝 序列化和反序列化
package main
import (
"fmt"
"google.golang.org/protobuf/proto"
pb "path/to/proto"
)
func main() {
// 创建消息
user := &pb.User{
Id: 1,
Name: "Alice",
Email: "alice@example.com",
Age: 30,
Role: pb.UserRole_USER_ROLE_MEMBER,
Active: true,
Tags: []string{"go", "protobuf"},
Profile: &pb.Profile{
Bio: "Go Developer",
SocialLinks: map[string]string{
"github": "alice",
"twitter": "@alice",
},
},
}
// 序列化
data, err := proto.Marshal(user)
if err != nil {
panic(err)
}
fmt.Printf("Serialized size: %d bytes\n", len(data))
// 反序列化
var user2 pb.User
if err := proto.Unmarshal(data, &user2); err != nil {
panic(err)
}
fmt.Printf("Deserialized: %+v\n", &user2)
}
JSON 互操作
📝 JSON 转换
import (
"google.golang.org/protobuf/encoding/protojson"
pb "path/to/proto"
)
func main() {
user := &pb.User{
Id: 1,
Name: "Alice",
}
// Protobuf → JSON
jsonData, err := protojson.Marshal(user)
if err != nil {
panic(err)
}
fmt.Println(string(jsonData))
// {"id":"1","name":"Alice"}
// JSON → Protobuf
var user2 pb.User
if err := protojson.Unmarshal(jsonData, &user2); err != nil {
panic(err)
}
}