一、更新一个消息类型

如果一个已有的消息格式已无法满足新的需求——如,要在消息中添加一个额外的字段——但是同时旧版本写的代码仍然可用。不用担心!更新消息而不破坏已有代码是非常简单的。在更新时只要记住以下的规则即可。

1.不要更改任何已有的字段的数值标识。

2.所添加的任何字段都必须是optional或repeated的。这就意味着任何使用“旧”的消息格式的代码序列化的消息可以被新的代码所解析,因为它们不会丢掉任何required的元素。应该为这些元素设置合理的默认值,这样新的代码就能够正确地与老代码生成的消息交互了。类似地,新的代码创建的消息也能被老的代码解析:老的二进制程序在解析的时候只是简单地将新字段忽略。然而,未知的字段是没有被抛弃的。此后,如果消息被序列化,未知的字段会随之一起被序列化——所以,如果消息传到了新代码那里,则新的字段仍然可用。注意:对Python来说,对未知字段的保留策略是无效的。

3.非required的字段可以移除——只要它们的标识号在新的消息类型中不再使用(更好的做法可能是重命名那个字段,例如在字段前添加“OBSOLETE_”前缀,那样的话,使用的.proto文件的用户将来就不会无意中重新使用了那些不该使用的标识号)。

4.一个非required的字段可以转换为一个扩展,反之亦然——只要它的类型和标识号保持不变。

5.int32, uint32, int64, uint64,和bool是全部兼容的,这意味着可以将这些类型中的一个转换为另外一个,而不会破坏向前、向后的兼容性。如果解析出来的数字与对应的类型不相符,那么结果就像在C++中对它进行了强制类型转换一样(例如,如果把一个64位数字当作int32来读取,那么它就会被截断为32位的数字)。

6.sint32和sint64是互相兼容的,但是它们与其他整数类型不兼容。

7.string和bytes是兼容的——只要bytes是有效的UTF-8编码。

8.嵌套消息与bytes是兼容的——只要bytes包含该消息的一个编码过的版本。

9.fixed32与sfixed32是兼容的,fixed64与sfixed64是兼容的。

二、扩展

通过扩展,可以将一个范围内的字段标识号声明为可被第三方扩展所用。然后,其他人就可以在他们自己的.proto文件中为该消息类型声明新的字段,而不必去编辑原始文件了。看个具体例子:

message Foo {

// …

extensions 100 to 199;

}

这个例子表明:在消息Foo中,范围[100,199]之内的字段标识号被保留为扩展用。现在,其他人就可以在他们自己的.proto文件中添加新字段到Foo里了,但是添加的字段标识号要在指定的范围内——例如:

extend Foo {

optional int32 bar = 126;

}

这个例子表明:消息Foo现在有一个名为bar的optional int32字段。

当用户的Foo消息被编码的时候,数据的传输格式与用户在Foo里定义新字段的效果是完全一样的。

然而,要在程序代码中访问扩展字段的方法与访问普通的字段稍有不同——生成的数据访问代码为扩展准备了特殊的访问函数来访问它。例如,下面是如何在C++中设置bar的值:

Foo foo;

foo.SetExtension(bar, 15);

类似地,Foo类也定义了模板函数 HasExtension(),ClearExtension(),GetExtension(),MutableExtension(),以及 AddExtension()。这些函数的语义都与对应的普通字段的访问函数相符。要查看更多使用扩展的信息,请参考相应语言的代码生成指南。注:扩展可 以是任何字段类型,包括消息类型。

1.嵌套的扩展

可以在另一个类型的范围内声明扩展,如:

message Baz {

extend Foo {

optional int32 bar = 126;

}

}

在此例中,访问此扩展的C++代码如下:

Foo foo;

foo.SetExtension(Baz::bar, 15);

一个通常的设计模式就是:在扩展的字段类型的范围内定义该扩展——例如,下面是一个Foo的扩展(该扩展是Baz类型的),其中,扩展被定义为了Baz的一部分:

message Baz {

extend Foo {

optional Baz foo_ext = 127;

}

}

然而,并没有强制要求一个消息类型的扩展一定要定义在那个消息中。也可以这样做:

message Baz {

}

extend Foo {

optional Baz foo_baz_ext = 127;

}

事实上,这种语法格式更能防止引起混淆。正如上面所提到的,嵌套的语法通常被错误地认为有子类化的关系——尤其是对那些还不熟悉扩展的用户来说。

2.选择可扩展的标符号

在同一个消息类型中一定要确保两个用户不会扩展新增相同的标识号,否则可能会导致数据的不一致。可以通过为新项目定义一个可扩展标识号规则来防止该情况的发生。

如果标识号需要很大的数量时,可以将该可扩展标符号的范围扩大至max,其中max是2^29 - 1, 或536,870,911。如下所示:

message Foo {

extensions 1000 to max;

}

通常情况下在选择标符号时,标识号产生的规则中应该避开[19000-19999]之间的数字,因为这些已经被Protocol Buffers实现中预留了。

三、包(Package)

当然可以为.proto文件新增一个可选的package声明符,用来防止不同的消息类型有命名冲突。如:

package foo.bar;

message Open { ... }

在其他的消息格式定义中可以使用包名+消息名的方式来定义域的类型,如:

message Foo {

...

required foo.bar.Open open = 1;

...

}

包的声明符会根据使用语言的不同影响生成的代码。对于C++,产生的类会被包装在C++的命名空间中,如上例中的Open会被封装在 foo::bar空间中;对于Java,包声明符会变为java的一个包,除非在.proto文件中提供了一个明确有java_package;对于 Python,这个包声明符是被忽略的,因为Python模块是按照其在文件系统中的位置进行组织的。

1.包及名称的解析

Protocol buffer语言中类型名称的解析与C++是一致的:首先从最内部开始查找,依次向外进行,每个包会被看作是其父类包的内部类。当然对于 (foo.bar.Baz)这样以“.”分隔的意味着是从最外围开始的。ProtocolBuffer编译器会解析.proto文件中定义的所有类型名。 对于不同语言的代码生成器会知道如何来指向每个具体的类型,即使它们使用了不同的规则。

原文

http://www.cnblogs.com/dkblog/archive/2012/03/27/2419010.html

protobuf 更新消息和扩展,包的更多相关文章

  1. 正确的 Composer 扩展包安装方法

    问题说明 我们经常要往现有的项目中添加扩展包,有时候因为文档的错误引导,如下图来自 这个文档 的: composer update 这个命令在我们现在的逻辑中,可能会对项目造成巨大伤害. 因为 com ...

  2. 使用 Composer 安装Laravel扩展包的几种方法

    使用 Composer 安装Laravel扩展包的几种方法 以下的三种方法都是需要你在项目的根目录运行 第一种:composer install 如有 composer.lock 文件,直接安装,否则 ...

  3. Composer 扩展包安装方法

    问题说明 我们经常要往现有的项目中添加扩展包,有时候因为文档的错误引导,如下图来自 这个文档 的: composer update 这个命令在我们现在的逻辑中,可能会对项目造成巨大伤害. 因为 com ...

  4. 如何正确使用 Composer 安装 Laravel 扩展包

    我们经常要往现有的项目中添加扩展包,有时候因为文档的错误引导,如下图来自 这个文档 的: composer update 这个命令在我们现在的逻辑中,可能会对项目造成巨大伤害. 因为 composer ...

  5. Visual Studio 2015的Web扩展包

    过去几年,Visual Studio扩展功能生态系统得到了蓬勃发展,社区贡献出了大量优秀的扩展,其中也包括大量针对Web开发的扩展.但是很多时候,感觉寻找.安装.更新好 几个扩展,总显得比较麻烦.如果 ...

  6. 【转】下载量最高的 100 个 Laravel 扩展包推荐

    说明 Laravel 另一个令人喜欢的地方,是拥有活跃的开发者社区,而活跃的开发者社区带来的,是繁华的扩展包生态. 本文对 Packagist 上打了 Laravel 标签 的扩展包进行整理,截止到现 ...

  7. laravel 安装 Laravel 扩展包

    问题说明 我们经常要往现有的项目中添加扩展包,有时候因为文档的错误引导,如下图来自这个文档 的: composer update 这个命令在我们现在的逻辑中,可能会对项目造成巨大伤害. 因为 comp ...

  8. FreeSql 扩展包实现 Dapper 的使用习惯

    简介 FreeSql.Connection.Extensions 这是 FreeSql 衍生出来的扩展包,实现(Mysql/postgresql/sqlserver/Oracle/SQLite)数据库 ...

  9. Python框架学习之Flask中的常用扩展包

    Flask框架是一个扩展性非常强的框架,所以导致它有非常多的扩展包.这些扩展包的功能都很强大.本节主要汇总一些常用的扩展包. 一. Flask-Script pip install flask-scr ...

随机推荐

  1. spark streaming限制吞吐

    使用spark.streaming.receiver.maxRate这个属性限制每秒的最大吞吐.官方文档如下: Maximum rate (number of records per second) ...

  2. Github如何撤销提交并清除痕迹

    1.在命令行工具中进入项目目录 cd /Users/mac.manon/workspace/QuickCodes 2.sudo git reset --hard HEAD~4 根据提示输入本系统登录密 ...

  3. 搞不清FastCgi与php-fpm之间是个什么样的关系

    我在网上查fastcgi与php-fpm的关系,查了快一周了,基本看了个遍,真是众说纷纭,没一个权威性的定义. 网上有的说,fastcgi是一个协议,php-fpm实现了这个协议: 有的说,php-f ...

  4. ref:linux查看用户登录时间以及命令历史

    ref:https://blog.csdn.net/csdn924618338/article/details/73555725/ 1.查看当前登录用户信息 who命令: who缺省输出包括用户名.终 ...

  5. oracle数据库连接错误解决办法

    ORA-28547 连接服务器失败,可能是Oracle Net 管理错误 原文地址:http://www.linuxidc.com/Linux/2014-11/109686.htm 上周去给客户培训O ...

  6. 关于ImportError: libssl.so.10: cannot open shared object file: No such file or directory unable to load app 0 (mountpoint='') (callable not found or import error)

    一.问题描述 在亚马逊云服务器使用Nginx+uwsgi部署django项目时,项目可以使用python manage.py runserver正常运行,uwsgi测试也没问题,Nginx也正常启动, ...

  7. java微信公众号JSAPI支付以及所遇到的坑

    上周做了个支付宝微信扫码支付,今天总结一下.微信相比支付宝要麻烦许多 由于涉及到代理商,没办法,让我写个详细的申请流程,懵逼啊. 笔记地址 http://note.youdao.com/notesha ...

  8. Bzoj4237 cdq分治+树状数组+单调栈

    二维平面在某区域内点的问题,要么树套树,kdtree,要么就是cdq分治了.然而这题树套树和kdtree都不是很好搞的样子,于是我们就只能cdq分治了.首先把点按照横坐标x排序,在每一层我们需要算出右 ...

  9. 最短路径:(Dijkstra & Floyd)

    Dijkstra算法 1.定义概览 Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止.Di ...

  10. bzoj 4004 向量拟阵

    题解RT. eps = 1e-10 WrongAnswer eps = 1e-5 Accepted /************************************************* ...