Protocol Buffers Sprachspezifikation (Proto3)
Die Syntax wird mithilfe von Extended Backus-Naur Form (EBNF) spezifiziert.
| alternation
() grouping
[] option (zero or one time)
{} repetition (any number of times)
Weitere Informationen zur Verwendung von proto3 finden Sie im Sprachleitfaden.
Lexikalische Elemente
Buchstaben und Ziffern
letter = "A" ... "Z" | "a" ... "z"
decimalDigit = "0" ... "9"
octalDigit = "0" ... "7"
hexDigit = "0" ... "9" | "A" ... "F" | "a" ... "f"
Bezeichner
ident = letter { letter | decimalDigit | "_" }
fullIdent = ident { "." ident }
messageName = ident
enumName = ident
fieldName = ident
oneofName = ident
mapName = ident
serviceName = ident
rpcName = ident
messageType = [ "." ] { ident "." } messageName
enumType = [ "." ] { ident "." } enumName
Ganzzahl-Literale
intLit = decimalLit | octalLit | hexLit
decimalLit = [-] ( "1" ... "9" ) { decimalDigit }
octalLit = [-] "0" { octalDigit }
hexLit = [-] "0" ( "x" | "X" ) hexDigit { hexDigit }
Gleitkomma-Literale
floatLit = [-] ( decimals "." [ decimals ] [ exponent ] | decimals exponent | "."decimals [ exponent ] ) | "inf" | "nan"
decimals = [-] decimalDigit { decimalDigit }
exponent = ( "e" | "E" ) [ "+" | "-" ] decimals
Boolean
boolLit = "true" | "false"
Zeichenketten-Literale
strLit = strLitSingle { strLitSingle }
strLitSingle = ( "'" { charValue } "'" ) | ( '"' { charValue } '"' )
charValue = hexEscape | octEscape | charEscape | unicodeEscape | unicodeLongEscape | /[^\0\n\\]/
hexEscape = '\' ( "x" | "X" ) hexDigit [ hexDigit ]
octEscape = '\' octalDigit [ octalDigit [ octalDigit ] ]
charEscape = '\' ( "a" | "b" | "f" | "n" | "r" | "t" | "v" | '\' | "'" | '"' )
unicodeEscape = '\' "u" hexDigit hexDigit hexDigit hexDigit
unicodeLongEscape = '\' "U" ( "000" hexDigit hexDigit hexDigit hexDigit hexDigit |
"0010" hexDigit hexDigit hexDigit hexDigit
EmptyStatement
emptyStatement = ";"
Konstante
constant = fullIdent | ( [ "-" | "+" ] intLit ) | ( [ "-" | "+" ] floatLit ) |
strLit | boolLit | MessageValue
MessageValue ist in der Text Format Language Specification definiert.
Syntax
Die Anweisung `syntax` wird verwendet, um die Protobuf-Version zu definieren.
syntax = "syntax" "=" ("'" "proto3" "'" | '"' "proto3" '"') ";"
Beispiel
syntax = "proto3";
Import-Anweisung
Die Import-Anweisung wird verwendet, um Definitionen aus anderen .proto-Dateien zu importieren.
import = "import" [ "weak" | "public" ] strLit ";"
Beispiel
import public "other.proto";
Paket
Der Paket-Spezifizierer kann verwendet werden, um Namenskonflikte zwischen Protokoll-Nachrichtentypen zu vermeiden.
package = "package" fullIdent ";"
Beispiel
package foo.bar;
Option
Optionen können in proto-Dateien, Nachrichten, Enums und Services verwendet werden. Eine Option kann eine von Protobuf definierte Option oder eine benutzerdefinierte Option sein. Weitere Informationen finden Sie unter Optionen im Sprachleitfaden.
option = "option" optionName "=" constant ";"
optionName = ( ident | bracedFullIdent ) { "." ( ident | bracedFullIdent ) }
bracedFullIdent = "(" ["."] fullIdent ")"
optionNamePart = { ident | "(" ["."] fullIdent ")" }
Beispiel
option java_package = "com.example.foo";
Felder
Felder sind die grundlegenden Elemente einer Protocol Buffer-Nachricht. Felder können normale Felder, Oneof-Felder oder Map-Felder sein. Ein Feld hat einen Typ und eine Feldnummer.
type = "double" | "float" | "int32" | "int64" | "uint32" | "uint64"
| "sint32" | "sint64" | "fixed32" | "fixed64" | "sfixed32" | "sfixed64"
| "bool" | "string" | "bytes" | messageType | enumType
fieldNumber = intLit;
Normales Feld
Jedes Feld hat Typ, Name und Feldnummer. Es kann Feldoptionen haben.
field = [ "repeated" | "optional" ] type fieldName "=" fieldNumber [ "[" fieldOptions "]" ] ";"
fieldOptions = fieldOption { "," fieldOption }
fieldOption = optionName "=" constant
Beispiele
foo.Bar nested_message = 2;
repeated int32 samples = 4 [packed=true];
Oneof und Oneof-Feld
Ein `oneof` besteht aus `oneof`-Feldern und einem `oneof`-Namen.
oneof = "oneof" oneofName "{" { option | oneofField } "}"
oneofField = type fieldName "=" fieldNumber [ "[" fieldOptions "]" ] ";"
Beispiel
oneof foo {
string name = 4;
SubMessage sub_message = 9;
}
Map-Feld
Ein Map-Feld hat einen Schlüsseltyp, einen Werttyp, einen Namen und eine Feldnummer. Der Schlüsseltyp kann jeder ganzzahlige Typ oder ein String-Typ sein.
mapField = "map" "<" keyType "," type ">" mapName "=" fieldNumber [ "[" fieldOptions "]" ] ";"
keyType = "int32" | "int64" | "uint32" | "uint64" | "sint32" | "sint64" |
"fixed32" | "fixed64" | "sfixed32" | "sfixed64" | "bool" | "string"
Beispiel
map<string, Project> projects = 3;
Reserviert
Reserved-Anweisungen deklarieren einen Bereich von Feldnummern oder Feldnamen, die in dieser Nachricht nicht verwendet werden dürfen.
reserved = "reserved" ( ranges | strFieldNames ) ";"
ranges = range { "," range }
range = intLit [ "to" ( intLit | "max" ) ]
strFieldNames = strFieldName { "," strFieldName }
strFieldName = "'" fieldName "'" | '"' fieldName '"'
Beispiele
reserved 2, 15, 9 to 11;
reserved "foo", "bar";
Top-Level-Definitionen
Enum-Definition
Die Enum-Definition besteht aus einem Namen und einem Enum-Body. Der Enum-Body kann Optionen, Enum-Felder und reservierte Anweisungen enthalten.
enum = "enum" enumName enumBody
enumBody = "{" { option | enumField | emptyStatement | reserved } "}"
enumField = ident "=" [ "-" ] intLit [ "[" enumValueOption { "," enumValueOption } "]" ]";"
enumValueOption = optionName "=" constant
Beispiel
enum EnumAllowingAlias {
option allow_alias = true;
EAA_UNSPECIFIED = 0;
EAA_STARTED = 1;
EAA_RUNNING = 2 [(custom_option) = "hello world"];
}
Nachrichtendefinition
Eine Nachricht besteht aus einem Nachrichtennamen und einem Nachrichtenkörper. Der Nachrichtenkörper kann Felder, verschachtelte Enum-Definitionen, verschachtelte Nachrichten-Definitionen, Optionen, `oneof`s, Map-Felder und `reserved`-Anweisungen enthalten. Eine Nachricht darf in demselben Nachrichtenschema nicht zwei Felder mit demselben Namen enthalten.
message = "message" messageName messageBody
messageBody = "{" { field | enum | message | option | oneof | mapField |
reserved | emptyStatement } "}"
Beispiel
message Outer {
option (my_option).a = true;
message Inner { // Level 2
int64 ival = 1;
}
map<int32, string> my_map = 2;
}
Keine der innerhalb einer Nachricht deklarierten Entitäten darf widersprüchliche Namen haben. Alle folgenden sind verboten
message MyMessage {
optional string foo = 1;
message foo {}
}
message MyMessage {
optional string foo = 1;
oneof foo {
string bar = 2;
}
}
message MyMessage {
optional string foo = 1;
enum E {
foo = 0;
}
}
Service-Definition
service = "service" serviceName "{" { option | rpc | emptyStatement } "}"
rpc = "rpc" rpcName "(" [ "stream" ] messageType ")" "returns" "(" [ "stream" ]
messageType ")" (( "{" {option | emptyStatement } "}" ) | ";")
Beispiel
service SearchService {
rpc Search (SearchRequest) returns (SearchResponse);
}
Proto-Datei
proto = [syntax] { import | package | option | topLevelDef | emptyStatement }
topLevelDef = message | enum | service
Ein Beispiel .proto-Datei
syntax = "proto3";
import public "other.proto";
option java_package = "com.example.foo";
enum EnumAllowingAlias {
option allow_alias = true;
EAA_UNSPECIFIED = 0;
EAA_STARTED = 1;
EAA_RUNNING = 1;
EAA_FINISHED = 2 [(custom_option) = "hello world"];
}
message Outer {
option (my_option).a = true;
message Inner { // Level 2
int64 ival = 1;
}
repeated Inner inner_message = 2;
EnumAllowingAlias enum_field = 3;
map<int32, string> my_map = 4;
}