proto2語法


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支持大多數基礎數據類型,下表包含常用類型,詳細列表見官方文檔

.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可以定義枚舉類型: ``` 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();

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM