一、Golang Protobuf 基础

67 阅读2分钟

一、基础理论

Protocol Buffers是语言无关,平台无关拓展机制,用于序列化结构数据。

ProtoBuf 解决的问题?

1.大小不超过几兆字节的类型化结构化数据数据包提供序列化格式
2.非常通用的数据结构用于文件存储格式和网络传输格式

开发者只需要定义.proto文件就可以生成各种语言对应的代码,例如:

message Person {
  optional string name = 1;
  optional int32 id = 2;
  optional string email = 3;
}

生成的Java代码

Person john = Person.newBuilder()
    .setId(1234)
    .setName("John Doe")
    .setEmail("jdoe@example.com")
    .build();
output = new FileOutputStream(args[0]);
john.writeTo(output);

ProtoBuf 的优点

1.紧凑的数据存储
2.快速解析
3.支出多种编程语言
4.通过自动生成的类优化功能

不适用 ProtoBuf 的场景

1.不适合处理较大的数据,超过几 MB 的数据
2.相同的数据可以具有许多不同的二进制序列化
3.消息不会压缩
4.涉及大型多维浮点数数组的许多科学和工程用途

二、代码示例

开发环境:
golang 1.20.1
protoc libprotoc 3.20.3

使用 Github create label的接口作为演示
Create Label 接口

代码目录结构

├── com
│   └── example
│       └──label
│          └──label.pb.go
├── go.mod
├── go.sum
├── label.proto
└── main.go
syntax = "proto3";

package label;

option go_package = "com/example/label";

message CreateLabelRequest{
  string name = 1;
  optional string color = 2;
  optional string description = 3;
}

message CreateLabelResponse{
  int64 id = 1;
  string node_id = 2;
  string url = 3;
  string name = 4;
  string description = 5;
  string color = 6;
  bool  default = 7;
}

message ListLabelRequest{
  string owner = 1;
  string repo = 2;
  int32 milestone_number = 3;
  optional int32 per_page = 4;
  optional int32 page = 5;
}

message ListLabelResponse{
  int32 code = 1;
  string message = 2;
  repeated CreateLabelResponse items = 3;
}

使用命令生成对应的 golang 文件

protoc --go_out=. *.proto

测试代码

package main

import (
	"example.com/com/example/label"
	"log"
)

func main() {

	label1 := label.CreateLabelRequest{
		Name:        "bug",
		Color:       nil,
		Description: nil,
	}
	log.Print(label1.String())

	color := "12345"
	description := "hello"
	label2 := label.CreateLabelRequest{
		Name:        "bug",
		Color:       &color,
		Description: &description,
	}
	log.Print(label2.String())

	labelResp := label.CreateLabelResponse{
		Id:          208045946,
		NodeId:      "MDU6TGFiZWwyMDgwNDU5NDY=",
		Url:         "https://api.github.com/repos/octocat/Hello-World/labels/bug",
		Name:        "bug",
		Description: "Something isn't working",
		Color:       "f29513",
		Default:     true,
	}
	log.Print(labelResp.String())

	perPage := int32(30)
	page := int32(1)
	label3 := label.ListLabelRequest{
		Owner:           "zhang san",
		Repo:            "example",
		MilestoneNumber: 1,
		PerPage:         &perPage,
		Page:            &page,
	}
	log.Print(label3.String())

	items := make([]*label.CreateLabelResponse, 0)
	for i := 0; i < 3; i++ {
		items = append(items, &label.CreateLabelResponse{
			Id:          int64(i),
			NodeId:      "1233545",
			Url:         "https://api.github.com/repos/octocat/Hello-World/labels/bug",
			Name:        "octocat",
			Description: "Hello-World",
			Color:       "#7f7f7f",
			Default:     true,
		})
	}
	label4 := label.ListLabelResponse{
		Code:    200,
		Message: "OK",
		Items:   items,
	}
	log.Print(label4.String())
}

输出结果


name:"bug"
name:"bug" color:"12345" description:"hello"
id:208045946 node_id:"MDU6TGFiZWwyMDgwNDU5NDY=" url:"https://api.github.com/repos/octocat/Hello-World/labels/bug" name:"bug" description:"Something isn't working" color:"f29513" default:true
owner:"zhang san" repo:"example" milestone_number:1 per_page:30 page:1
code:200 message:"OK" items:{node_id:"1233545" url:"https://api.github.com/repos/octocat/Hello-World/labels/bug" name:"octocat" description:"Hello-World" color:"#7f7f7f" default:true} items:{id:1 node_id:"1233545" url:"https://api.github.com/repos/octocat/Hello-World/labels/bug" name:"octocat" description:"Hello-World" color:"#7f7f7f" default:true} items:{id:2 node_id:"1233545" url:"https://api.github.com/repos/octocat/Hello-World/labels/bug" name:"octocat" description:"Hello-World" color:"#7f7f7f" default:true}

初步了解 ProtoBuf 的优缺点和使用的场景, 简单写了一些代码。