Language Guide (proto3) | proto3 语言指南(九)Oneof结构
Oneof - Oneof结构
如果消息包含多个字段,并且最多只能同时设置一个字段,则可以使用oneof功能强制执行此行为并节省内存。
oneof字段与常规字段类似,但oneof共享内存中的所有字段除外,并且oneof最多只能同时设置一个字段。设置oneof的任何成员将自动清除所有其他成员。您可以使用特殊的case()或WhichOneof()方法检查oneof中设置了哪个值(如果有被设置),具体取决于您选择的语言。
使用oneof结构
要在.proto中定义oneof结构,请使用oneof关键字后跟oneof名称。请看示例test_oneof:
message SampleMessage {
oneof test_oneof {
string name = 4;
SubMessage sub_message = 9;
}
}
然后将oneof字段添加到oneof定义。你可以添加任意类型的字段,除了map和repeated类型的字段。
在生成的代码中,oneof字段与常规字段一样具有getter(访问器)和setter(设置器)。您还可以使用一种特殊的方法来检查oneof结构中设置了哪个值(如果有的话)。您可以在相关的API参考中找到有关所选语言的oneof API的更多信息。
oneof的功能
- 设置oneof字段将自动清除oneof的所有其他成员。因此,如果您设置了几个字段中的一个,那么只有最后设置的字段有效。
SampleMessage message;
message.set_name("name");
CHECK(message.has_name());
message.mutable_sub_message(); // Will clear name field.
CHECK(!message.has_name());
- 如果解析器在
wire上遇到同一个oneof的多个成员,则在解析的消息中只使用看到的最后一个成员。 oneof结构不能使用repeated修饰符。- 反射API适用于
oneof字段。 - 如果将
oneof字段设置为默认值(例如将int32类型的oneof字段设置为0),则将设置该oneof字段的case,并且该值将在wire上序列化。 - 如果使用
C++,请确保代码不会导致内存崩溃。下面的示例代码将崩溃,因为在调用set_name()方法时已经删除了sub_message。
SampleMessage message;
SubMessage* sub_message = message.mutable_sub_message();
message.set_name("name"); // Will delete sub_message
sub_message->set_... // Crashes here
- 同样在
C++中,如果你使用Swap()方法交换两条使用了oneof结构的消息,每条消息都将以另外一条消息的oneof case结束:在下面的示例中,msg1将有一个sub_message字段,msg2将有一个name字段。
SampleMessage msg1;
msg1.set_name("name");
SampleMessage msg2;
msg2.mutable_sub_message();
msg1.swap(&msg2);
CHECK(msg1.has_sub_message());
CHECK(msg2.has_name());
向后(下)兼容问题
添加或删除oneof字段时要小心。如果检查oneof字段的值返回None/NOT_SET,则可能意味着此oneof尚未设置或已将其设置为oneof的其他版本中的字段。因为无法知道wire的未知字段是否是其中一个字段的成员,所以无法区分两者之间的区别。
标签重用问题
- 将字段移入或移出
oneof:消息序列化和解析后,可能会丢失一些信息(某些字段将被清除)。但是,您可以安全地将single字段移动到新的oneof字段中,并且如果已知只设置了一个字段,则可以移动多个字段。 - 删除
oneof字段并将其加回:这可能会在序列化和解析消息后清除当前设置的oneof字段。 - 拆分或合并
oneof字段:这与移动常规字段有类似的问题
Language Guide (proto3) | proto3 语言指南(九)Oneof结构的更多相关文章
- Swift语言指南(九)--基本运算符
原文:Swift语言指南(九)--基本运算符 运算符(operator)是用来检查,改变或合并值的一种特殊符号或短语.例如,加号运算符让两个数字相加(如:let i = 1 + 2),还有些更复杂的运 ...
- Swift5 语言指南(九) 闭包
闭包是自包含的功能块,可以在代码中传递和使用.Swift中的闭包类似于C和Objective-C中的块以及其他编程语言中的lambdas. 闭包可以从定义它们的上下文中捕获和存储对任何常量和变量的引用 ...
- Language Guide (proto3) | proto3 语言指南(开篇)
前言 近日在学习gRPC框架的相关知识时接触到Protobuf(protocol-buffers,协议缓冲区),proto3等知识.网上很多文章/帖子经常把gRPC与proto3放在一起,为避免初学者 ...
- Language Guide (proto3) | proto3 语言指南(十五)生成类
Generating Your Classes - 生成类 要生成Java.Python.C++.Go.Ruby.ObjuleC或C代码,需要使用.proto文件中定义的消息类型,还需要在.proto ...
- Language Guide (proto3) | proto3 语言指南(十四)选项
Options - 选项 .proto文件中的单个声明可以使用许多 选项 进行注释.选项不会更改声明的总体含义,但可能会影响在特定上下文中处理声明的方式.可用选项的完整列表在google/protob ...
- Language Guide (proto3) | proto3 语言指南(十二)定义服务
Defining Services - 定义服务 如果要在RPC(Remote Procedure Call,远程过程调用)系统中使用消息类型,可以在.proto文件中定义RPC服务接口,协议缓冲区编 ...
- Protobuf 语言指南(proto3)
Protobuf 语言指南(proto3) Protocol Buffer是Google的语言中立的,平台中立的,可扩展机制的,用于序列化结构化数据 - 对比XML,但更小,更快,更简单.您可以定义数 ...
- Protocol Buffers(Protobuf) 官方文档--Protobuf语言指南
Protocol Buffers(Protobuf) 官方文档--Protobuf语言指南 约定:为方便书写,ProtocolBuffers在下文中将已Protobuf代替. 本指南将向您描述如何使用 ...
- Protobuf语言指南(转)
Protobuf语言指南 l 定义一个消息(message)类型 l 标量值类型 l Optional 的字段及默认值 l 枚举 l 使用其他消息类型 l 嵌套类型 l 更新一个消息类型 ...
随机推荐
- Redis基础篇(六)数据同步:主从复制
Redis具有高可靠性,体现在两方面: 一是数据尽量少丢失,通过前面介绍的持久化方式AOF和RDB,在宕机时可以恢复数据. 二是服务尽量少中断,通过副本冗余来实现. 今天我们学习的就是通过主从复制实现 ...
- 配置NFS实现nginx动静分离
案例子任务一.安装配置NFS服务器 步骤1:使用docker容器配置NFS服务器 启动centos容器并进入 docker run -d --privileged centos:v1 /usr/sbi ...
- redis 作为 mysql的缓存服务器(读写分离)
redis 作为 mysql的缓存服务器(读写分离) 一.redis简介 Redis是一个key-value存储系统.和Memcached类似,为了保证效率,数据都是缓存在内存中.区别的是redis会 ...
- Nginx安装,开箱即用?
一.官网 首页:http://nginx.org/ 下载地址:http://nginx.org/download 安装文档:http://nginx.org/en/docs/install.html ...
- Spring源码深度解析之事务
Spring源码深度解析之事务 目录 一.JDBC方式下的事务使用示例 (1)创建数据表结构 (2)创建对应数据表的PO (3)创建表和实体之间的映射 (4)创建数据操作接口 (5)创建数据操作接口实 ...
- 用percona monitoring plugins 监控mysql
下载:http://www.percona.com/redir/downloads/percona-monitoring-plugins/1.1.1/percona-zabbix-templates- ...
- 【Oracle】想查询相关的v$视图,但是提示表或视图不存在解决办法
原因是使用的用户没有相关的查询权限导致 解决办法: grant select any dictionary to 用户; --这个权限比较大 这个权限是最低的要求,但是可以访问到v$相关视图 ...
- Java中,那些关于String和字符串常量池你不得不知道的东西
老套的笔试题 在一些老套的笔试题中,会要你判断s1==s2为false还是true,s1.equals(s2)为false还是true. String s1 = new String("xy ...
- JVM虚拟机基础
JVM 全称Java Virtual Machine,也就是我们耳熟能详的Java 虚拟机.它能识别.class 后缀的文件,并且能够解析它的指令,最终调用操作系统上的函数,完成我们想要的操作. Ja ...
- Django Signals
信号 Django中提供了"信号调度",用于在框架执行操作时解耦.通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒一些接受者. Django内置的信号 Model si ...