proto 2 语法
一、proto文件
PB的定义是通过proto文件进行定义的,一个标准的类型如下:
1 2 3 4 5 | message SearchRequest { required string query = 1 ; optional int32 page_number = 2 [ default = 10 ]; optional int32 result_per_page = 3 ; } |
其中message定义了类型名字,其中每一个字段有三个选项:
- required:字段必填。
- optional: 字段选填,不填就会使用默认值,默认数值类型的默认值为0,string类型为空字符串,枚举类型为第一个枚举值。
- repeated: 数组类型,可以放入多个类型实例。
之后需要跟上数据类型,在类型之后为字段名。最后跟上“=N”这里N是标记位,每个字段都有标记位,各个字段不能重复且必须为正值,其最大值为 2^29 - 1,同时protobuf内部预留了19000到19999不能被用户使用,官方建议将常用的字段放在前面,由于这个字段的大小随着数值大小增加,如1-16只占用一个字节。最后可以跟上自定义的默认值。
在一个proto文件中可以存放多个message,message内部也可以定义message,外部如需调用需要指明对应的层级关系。同时可以使用import引入外部的proto文件:
1 2 3 4 | //引入外部proto文件 import "other.proto" ; //引入外部proto文件,并让引入了该文件的proto文件也能访问被引入类型。 import public "other.proto" ; |
还可以在proto文件中各个级别增加部分编译设置,常用包括:
- java_package:生成的java包名
- java_outer_classname :生成的java类名
- optimize_for:设置编译优化级别,SPEED-默认值速度优先,CODE_SIZE-最小代码量,LITE_RUNTIME-最小运行时占用(适用于环境受限的情况)
二、数据类型
基础数据类型
protobuf支持大多数基础数据类型,下表包含常用类型,详细列表见官方文档
.proto | java实现 | desc |
---|---|---|
double | double | |
float | float | |
int32 | int | 有符号整形建议使用sint32 |
uint32 | int | 无符号整形 |
sint32 | int | 有符号整形 |
int64 | long | 有符号长整形建议使用sint64 |
uint64 | long | 无符号长整形 |
sint64 | long | 有符号长整形 |
bool | boolean | |
string | String | |
byte | ByteString |
枚举类型
protobuf可以定义枚举类型:
1 2 3 4 5 | enum EnumType { TYPEA = 0 ; TYPEB = 1 ; TYPEC = 2 ; } |
enum的每行字段都是一个枚举值,等号后面跟的是实际值,默认实际值是不能一样的,但只需要增加一个option配置就可以设置一样的值:
1 2 3 4 5 6 | enum EnumType { option allow_alias = true ; TYPEA = 0 ; TYPEB = 0 ; TYPEC = 2 ; } |
自定义数据类型
还有就是自定义的message类型:
1 2 3 4 5 6 7 | message MessageType { repeated string str = 1 ; } message CompositeType { optional MessageType message = 1 ; } |
oneof
oneof是一种特殊类型可以绑定一组变量,但是只有最后设置的那个变量才生效,之前的变量都会被清除:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | -------proto------ message Foo { oneof test_oneof { string name = 1 ; int32 id = 2 ; } } -------java------- System.out.println(Demo.Foo.newBuilder().setId( 1 ).setName( "name" ).build().toString()); System.out.println( ">>>" ); System.out.println(Demo.Foo.newBuilder().setName( "name" ).setId( 1 ).build().toString()); -------输出------- name: "name" >>> id: 1 |
map
map类型可以接受键值对,键可以使用string或数值类型,值可以使用任意类型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | -------proto------ message Foo { map<string, string> bar = 1 ; } -------java------- Demo.Foo foo=Demo.Foo.newBuilder().putBar( "key1" , "value1" ).putBar( "key2" , "value2" ).build(); FileOutputStream fos= new FileOutputStream( "D://person" ); foo.writeTo(fos); fos.close(); FileInputStream fis= new FileInputStream( "D://person" ); Demo.Foo foo2=Demo.Foo.parseFrom(fis); System.out.println(foo2.getBarCount()); fis.close(); |
extension
Extension有点类似继承,可以向message对象内增加额外的字段:
1 2 3 4 5 6 7 8 | message Foo { // ... extensions 100 to 199 ; //首先需要定义100-199为extension字段 } extend Foo { optional int32 bar = 100 ; //增加bar字段 } |
在使用extension时和普通字段有些不同,Java中如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public static void main(String[] args) throws IOException, ClassNotFoundException { //通过setExtension设置字段值 Demo.Foo foo=Demo.Foo.newBuilder().setExtension(Demo.bar, 1 ).build(); //通过getExtension可以取值 System.out.println(foo.getExtension(Demo.bar)); FileOutputStream fos= new FileOutputStream( "D://person" ); foo.writeTo(fos); fos.close(); FileInputStream fis= new FileInputStream( "D://person" ); //反序列化时需要注册对应的extension字段,不然无法取到extesion的值 ExtensionRegistry registry = ExtensionRegistry.newInstance(); registry.add(Demo.bar); Demo.Foo foo2=Demo.Foo.parseFrom(fis,registry); System.out.println(foo2.getExtension(Demo.bar)); fis.close(); } |
分类:
protocol buffer
标签:
protocol buffer
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(三):用.NET IoT库
· 【非技术】说说2024年我都干了些啥