Go with Protobuf

这篇具有很好参考价值的文章主要介绍了Go with Protobuf。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

原文在这里。

本教程为 Go 程序员提供了使用Protocol buffer的基本介绍。

本教程使用proto3向 Go 程序员介绍如何使用 protobuf。通过创建一个简单的示例应用程序,它向你展示了如何:

  • .proto中定义消息格式
  • 使用protocol buffer编译器
  • 使用Go protocol buffer API读写消息

这并不是protocol buffer在Go中使用的完整指南。更多细节,详见Protocol Buffer Language Guide、Go API Reference、Go Generated Code Guide和Encoding Reference。

为什么使用Protocol Buffer

我们要使用的例子是一个非常简单的“通讯录”应用程序,它可以从文件中读写联系人的信息。通讯录中每个人都有一个姓名、ID、邮箱和练习电话。

你如何序列化并取回这样结构化的数据呢?下面有几条建议:

  • 原始内存中数据结构可以发送/保存为二进制。这是一种随时间推移而变得脆弱的方法,因为接收/读写的代码必须编译成相同的内存布局,endianness等。另外,文件已原始格式积累数据和在网络中到处传输副本,因此扩展这种格式十分困难。
  • 你可以编写已临时的方法来讲数据元素编码到单个字符串中 --- 例如用“12:3:-23:67”来编码4个int。这是一种简单而灵活的方法,尽管它确实需要编写一次性的编码和解析代码,并且解析会增加少量的运行时成本。这对于编码非常简单的数据最有效。
  • 序列化为XML。这种方法非常有吸引力,因为XML(某种程度上)是人类可读的,而且有许多语言的绑定库。如果你希望与其他应用程序/项目共享数据,这可能是一个不错的选择。然而,XML是出了名的空间密集型,对它进行编码/解码会给应用程序带来巨大的性能损失。而且,在XML DOM树中导航要比在类中导航简单字段复杂得多。

Protocol buffers是解决这个问题的灵活、高效、自动化的解决方案。使用Protocol buffers,你编写一个描述要存储的数据结构的.proto文件。然后,Protocol buffer编译器会创建一个类,该类实现了Protocol buffer数据的自动编码和解析,使用高效的二进制格式。生成的类为构成Protocol buffer的字段提供了获取器和设置器,并处理了读取和写入Protocol buffer的细节。重要的是,Protocol buffer格式支持随着时间的推移扩展格式的想法,以使代码仍然能够读取使用旧格式编码的数据。

从哪能找到示例代码呢?

我们的示例是一组用Protocol buffer编码的命令行应用程序,用于管理地址簿数据文件。命令add_person_go用于向数据文件添加新条目。命令list_people_go解析数据文件并将数据打印到控制台。

你可以从这里下载。

定义Protocol文件

通讯录程序从定义.proto文件开始。.proto文件中的定义很简单:为要序列化的每个数据结构添加一个message,然后为消息中的每个字段指定名称和类型。在我们的示例中,定义消息的.proto文件是addressbook.proto

.proto文件以一个包声明开头,这有助于防止不同项目之间的命名冲突。

syntax = "proto3";
package tutorial;

import "google/protobuf/timestamp.proto";

go_package选项定义了包含此文件中所有生成代码的包的导入路径。 Go包名称将是导入路径的最后一个路径组件。例如,我们的示例将使用“tutorialpb”作为包名称。

option go_package = "github.com/protocolbuffers/protobuf/examples/go/tutorialpb";

接下来,需要定义message。消息只是一个包含一组类型化字段的聚合。许多标准简单数据类型都可用作字段类型,包括boolint32floatdoublestring。你也可以通过使用其他消息类型作为字段类型来为消息添加更多结构。

message Person {
  string name = 1;
  int32 id = 2;  // Unique ID number for this person.
  string email = 3;

  enum PhoneType {
    PHONE_TYPE_UNSPECIFIED = 0;
    PHONE_TYPE_MOBILE = 1;
    PHONE_TYPE_HOME = 2;
    PHONE_TYPE_WORK = 3;
  }

  message PhoneNumber {
    string number = 1;
    PhoneType type = 2;
  }

  repeated PhoneNumber phones = 4;

  google.protobuf.Timestamp last_updated = 5;
}

// Our address book file is just one of these.
message AddressBook {
  repeated Person people = 1;
}

在上面例子中,Person消息包含PhoneNumber消息,同时Person消息包含在AddressBook消息中。你甚至可以定义消息类型嵌套在其它消息中 --- 就像上面PhoneNumber定义在Person中。你也可以定义enum类型,如果你想让你的字段只是用预定义列表中的一个值 --- 这里你想声明的电话类型可以是MOBILEHOMEWORK其中之一。

“= 1”,“= 2”标记每个字段在二进制编码中的唯一的“tag”。序号1-15编码的字节数比较高的数字少一位,因此,作为一种优化,你可以决定对常用或重复的元素使用这些标记,而对不常用的可选元素使用标记16或更高。重复字段中的每个元素都需要重新编码标记号,因此重复字段是此优化的特别好的候选项。

如果未设置字段值,则会使用默认值:对于数字类型,使用零;对于字符串,使用空字符串;对于布尔值,使用false。对于嵌套的消息,默认值始终是消息的“默认实例”或“原型”,该实例没有任何字段设置。调用访问器以获取未明确设置的字段的值始终返回该字段的默认值。

如果字段是repeated的,那么该字段可以重复任意次数(包括零次)。重复值的顺序将由protocol buffer处理。可以将重复字段视为动态大小的数组。

你可以在Protocol Buffer语言指南中找到撰写.proto文件的完整指南,包括所有可能的字段类型。但不要寻找类继承类似的功能 - 因为protocol buffer不支持这一点。

编译Protocol Buffers

现在你已经有.proto文件了,接下来你需要生成读写AddressBook(包括PersonPhoneNumber)消息的类。现在,你需要运行protocol buffer编译器protoc

  • 如果你还没安装编译器,可从这里下载并根据README编译安装。
  • 使用如下命令按照Go protocol buffers插件:
    $ go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
    
    protoc-gen-go编译器插件将安装在$GOBIN中,默认为$GOPATH/bin。protocol buffer编译器protoc必须能够在你的$PATH中找到它。
  • 现在运行编译器,指明源目录(应用程序源文件目录,不指定的话默认使用当前目录),目标路径(你要存放生成的代码的目录,通常与$SRC_DIR一样),.proto文件路径。这样,你可以:
    $ protoc -I=$SRC_DIR --go_out=$DST_DIR $SRC_DIR/addressbook.proto
    
    因为要生成Go代码,所以使用--go_out选项。若要生成其它支持的语言,提供类似选项即可。
    生成的github.com/protocolbuffers/protobuf/examples/go/tutorialpb/addressbook.pb.go文件将保存在你指定的目录下。

Protocol Buffer API

生成的addressbook.pb.go为你提供了下面这些有用的类型:

  • 包含People字段的AddressBook结构体
  • 包含NameIdEmailPhones字段的People
  • 包含NumberType字段的Person_PhoneNumber
  • 自定义枚举类型的Person.PhoneType

你可以在Go 生成的代码指南中详细了解生成的代码的细节,但在大多数情况下,你可以将这些代码视为完全普通的 Go 类型。

以下是list_people命令的单元测试示例,演示了如何创建一个Person实例:

p := pb.Person{
    Id:    1234,
    Name:  "John Doe",
    Email: "jdoe@example.com",
    Phones: []*pb.Person_PhoneNumber{
        {Number: "555-4321", Type: pb.Person_PHONE_TYPE_HOME},
    },
}

创建Message

使用protocol buffers的目的是将数据序列化,以便在其他地方进行解析。在 Go 中,你可以使用proto库的Marshal函数来序列化你的protocol buffers数据。protocol buffers消息的结构体指针实现了proto.Message接口。调用proto.Marshal返回编码后的protocol buffers数据。例如,我们在add_person命令中使用了这个函数:

book := &pb.AddressBook{}
// ...

// Write the new address book back to disk.
out, err := proto.Marshal(book)
if err != nil {
    log.Fatalln("Failed to encode address book:", err)
}
if err := ioutil.WriteFile(fname, out, 0644); err != nil {
    log.Fatalln("Failed to write address book:", err)
}

读取Message

要解析已编码的消息,可以使用proto库的Unmarshal函数。调用此函数将数据解析为protocol buffers,并将结果放book中。因此,要在list_people命令中解析文件,我们使用以下代码:

// Read the existing address book.
in, err := ioutil.ReadFile(fname)
if err != nil {
    log.Fatalln("Error reading file:", err)
}
book := &pb.AddressBook{}
if err := proto.Unmarshal(in, book); err != nil {
    log.Fatalln("Failed to parse address book:", err)
}

扩展

在发布protocol buffer生成的代码后不久,你肯定会想提升你的protocol buffer定义。如果你想新的buffer可以被后向兼容,并且旧的buffer可以被前向兼容,--- 你确实想这样做 --- 那你需要遵守下面的规则。在新版的protocol buffer中:

  • 必须不能改变已有字段的序号。
  • 可以删除repeated字段。
  • 可以新增repeated字段,但必须使用新的序号(序号在protocol buffer中没被用过,也没被删除)。

还有一些其它的扩展要遵守,但很少会用到它们。

遵循这些规则,旧代码将可以轻松地读取新的消息,并且会忽略任何新字段。对于旧代码来说,已删除的单字段将只是它们的默认值,而已删除的重复字段将为空。新代码也可以透明地读取旧消息。

但请记住,旧消息中不会包含新字段,因此你需要合理地处理默认值。使用类型特定的默认值:对于字符串,默认值是空字符串。对于布尔值,默认值是false。对于数值类型,默认值是零。


Go with Protobuf

声明:本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)进行许可,使用时请注明出处。
Author: mengbin
blog: mengbin
Github: mengbin92
cnblogs: 恋水无意文章来源地址https://www.toymoban.com/news/detail-710664.html


到了这里,关于Go with Protobuf的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 小程序入门笔记(一) 黑马程序员前端微信小程序开发教程

    微信小程序基本介绍 小程序和普通网页有以下几点区别: 运行环境:小程序可以在手机的操作系统上直接运行,如微信、支付宝等;而普通网页需要在浏览器中打开才能运行。 开发技术:小程序采用前端技术进行开发,如HTML、CSS、JavaScript等;而普通网页也是使用类似的前

    2024年02月08日
    浏览(65)
  • 逢七拍手游戏--课后程序(Python程序开发案例教程-黑马程序员编著-第3章-课后作业)

    逢7拍手游戏的规则是:从1开始顺序数数,数到有7或者包含7的倍数的时候拍手。本实例要求编写程序,模拟实现逢七拍手游戏,输出100以内需要拍手的数字。 掌握for循环与range()函数的使用 掌握字符串中find()方法的使用 判断一个数字是否与7相关,可分为两种情况: 1.是否为

    2024年02月06日
    浏览(87)
  • 手机通讯录--课后程序(Python程序开发案例教程-黑马程序员编著-第5章-课后作业)

    通讯录是记录了联系人姓名和联系方式的名录,手机通讯录是最常见的通讯录之一,人们可以在通讯录中通过姓名查看相关联系人的联系方式、邮箱、地址等信息,也可以在其中新增联系人,或修改、删除联系人信息。下面是一个常见通讯录的功能菜单,如图1所示。   图1

    2024年02月01日
    浏览(59)
  • 银行管理系统--课后程序(Python程序开发案例教程-黑马程序员编著-第7章-课后作业)

    从早期的钱庄到现如今的银行,金融行业在不断地变革;随着科技的发展、计算机的普及,计算机技术在金融行业得到了广泛的应用。银行管理系统是一个集开户、查询、取款、存款、转账、锁定、解锁、退出等一系列的功能的管理系统,该系统中各功能的介绍如下。 开户功

    2024年02月04日
    浏览(51)
  • 中文数字对照表--课后程序(Python程序开发案例教程-黑马程序员编著-第4章-课后作业)

    阿拉伯数字因其具有简单易写、方便使用的特点成为了最流行的数字书写方式,但在使用阿拉伯数字计数时,可以对某些数字不漏痕迹的修改成其它数字,例如,将数字“1”修改为数字“7”,将数字“3”修改为数字“8”。为了避免引起不必要的麻烦,可以使用中文大写数字

    2024年02月05日
    浏览(77)
  • [学习笔记]黑马程序员-Hadoop入门视频教程

    黑马程序员大数据Hadoop入门视频教程,适合零基础自学的大数据Hadoop教程 学习目标 1.理解大数据基本概念 2.掌握数据分析基本步骤 3.理解分布式、集群概念 4.学会VMware虚拟机的导入与使用 5.掌握Linux常用操作命令使用 6.掌握vi/vim编辑器基础使用 1.1.1 企业数据分析方向 数据分

    2024年02月13日
    浏览(57)
  • [黑马程序员Pandas教程]——Pandas快速体验

    目录: 为什么要使用Python做数据开发 Python在数据开发领域的优势 为什么要学习Pandas 其他常用Python库介绍 主要内容介绍 Anaconda安装 Anaconda的虚拟环境管理 虚拟环境的作用 可以通过Anaconda界面创建虚拟环境 通过命令行创建虚拟环境 通过Anaconda管理界面安装包 也可以通过anac

    2024年02月06日
    浏览(52)
  • 图书管理系统登录页面--课后程序(Python程序开发案例教程-黑马程序员编著-第12章-课后作业)

    登录与注册是程序中最基本的模块。用户只有登录成功后,才可以使用应用系统中的全部功能。若用户没有登录账号,可通过注册界面设置登录账号信息。某图书管理系统的登录窗口如图1所示。   登录界面 图1的窗口中包含用户名、密码、验证码、登录、注册、退出。当用户

    2024年02月03日
    浏览(52)
  • 日记本-课后程序(JAVA基础案例教程-黑马程序员编著-第七章-课后作业)

    【实验7-3】  日记本 【任务介绍】   1. 任务描述 编写一个日记本功能的程序,使用字节流经日记的具体信息记录在本地的txt文件中。当用户输入日记的特定内容后,会将输入的内容保存至本地的txt文件中。需要输入的内容包括“姓名”,“天气”、“标题”、“内容”的数

    2024年02月05日
    浏览(55)
  • 学生管理系统-课后程序(JAVA基础案例教程-黑马程序员编著-第六章-课后作业)

    【案例6-2】 学生管理系统 【案例介绍】 1.任务描述 在一所学校中,对学生人员流动的管理是很麻烦的,本案例要求编写一个学生管理系统,实现对学生信息的添加、删除、修改和查询功能。每个功能的具体要求如下: 系统的首页:用于显示系统所有的操作,并根据用户在控

    2024年02月03日
    浏览(64)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包