proto2语法

本文详细介绍了protobuf的使用方式,包括如何定义消息类型、枚举类型、自定义类型等,同时还介绍了protobuf的一些高级特性如oneof、map及extension。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

proto文件

protobuf的定义是通过proto文件进行定义的,一个标准的类型如下:

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文件:

//引入外部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支持大多数基础数据类型,下表包含常用类型,详细列表见官方文档

.protojava实现desc
doubledouble
floatfloat
int32int有符号整形建议使用sint32
uint32int无符号整形
sint32int有符号整形
int64long有符号长整形建议使用sint64
uint64long无符号长整形
sint64long有符号长整形
boolboolean
stringString
byteByteString

枚举类型

protobuf可以定义枚举类型:

enum EnumType {
    TYPEA = 0;
    TYPEB = 1;
    TYPEC = 2;
}

enum的每行字段都是一个枚举值,等号后面跟的是实际值,默认实际值是不能一样的,但只需要增加一个option配置就可以设置一样的值:

enum EnumType {
   option allow_alias = true;
   TYPEA = 0;
   TYPEB = 0;
   TYPEC = 2;
}

自定义数据类型

还有就是自定义的message类型:

message MessageType {
  repeated string str = 1;
}

message CompositeType {
  optional MessageType message = 1;
}

oneof

oneof是一种特殊类型可以绑定一组变量,但是只有最后设置的那个变量才生效,之前的变量都会被清除:

-------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或数值类型,值可以使用任意类型:

-------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对象内增加额外的字段:

message Foo {
  // ...
  extensions 100 to 199;    //首先需要定义100-199为extension字段
}

extend Foo {
  optional int32 bar = 100; //增加bar字段
}

在使用extension时和普通字段有些不同,Java中如下:

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();
}

转载于:https://www.cnblogs.com/resentment/p/6539021.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值