Protocol Buffers Edition 2023 Sprachspezifikation
Die Syntax wird mithilfe von Extended Backus-Naur Form (EBNF) spezifiziert.
| alternation
() grouping
[] option (zero or one time)
{} repetition (any number of times)
Lexikalische Elemente
Buchstaben und Ziffern
letter = "A" ... "Z" | "a" ... "z"
capitalLetter = "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
streamName = ident
messageType = [ "." ] { ident "." } messageName
enumType = [ "." ] { ident "." } enumName
groupName = capitalLetter { letter | decimalDigit | "_" }
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.
Edition
Die Edition-Anweisung ersetzt das veraltete Schlüsselwort syntax und wird verwendet, um die Edition zu definieren, die diese Datei verwendet.
edition = "edition" "=" [ ( "'" decimalLit "'" ) | ( '"' decimalLit '"' ) ] ";"
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 Diensten verwendet werden. Eine Option kann eine von Protocol Buffers definierte Option oder eine benutzerdefinierte Option sein. Weitere Informationen finden Sie unter Optionen im Sprachleitfaden. Optionen werden auch verwendet, um Feature-Einstellungen zu steuern.
option = "option" optionName "=" constant ";"
optionName = ( ident | "(" ["."] fullIdent ")" )
Beispiele
option java_package = "com.example.foo";
option features.enum_type = CLOSED;
Felder
Felder sind die grundlegenden Elemente einer Protocol Buffer-Nachricht. Felder können normale Felder, Gruppenfelder, Oneof-Felder oder Map-Felder sein. Ein Feld hat ein Label, einen Typ und eine Feldnummer.
label = [ "repeated" ]
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 ein Label, einen Typ, einen Namen und eine Feldnummer. Es kann Feldoptionen haben.
field = [label] 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-Felder haben keine Labels.
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 oder Zeichenkettentyp sein. Beachten Sie, dass der Schlüsseltyp kein Enum sein darf.
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;
Erweiterungen und Reservierungen
Erweiterungen und reservierte Felder sind Nachrichtenelemente, die einen Bereich von Feldnummern oder Feldnamen deklarieren.
Erweiterungen (Extensions)
Erweiterungen deklarieren, dass ein Bereich von Feldnummern in einer Nachricht für Erweiterungen von Drittanbietern verfügbar ist. Andere Personen können neue Felder für Ihren Nachrichtentyp mit diesen numerischen Tags in ihren eigenen .proto-Dateien deklarieren, ohne die Originaldatei bearbeiten zu müssen.
extensions = "extensions" ranges ";"
ranges = range { "," range }
range = intLit [ "to" ( intLit | "max" ) ]
Beispiele
extensions 100 to 199;
extensions 4, 20 to max;
Reserviert
Reserviert deklariert einen Bereich von Feldnummern oder Namen in einer Nachricht oder einem Enum, der nicht verwendet werden kann.
reserved = "reserved" ( ranges | reservedIdent ) ";"
fieldNames = 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 = fieldName "=" [ "-" ] 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"];
}
Nachrichten-Definition
Eine Nachricht besteht aus einem Nachrichtennamen und einem Nachrichtenkörper. Der Nachrichtenkörper kann Felder, verschachtelte Enum-Definitionen, verschachtelte Nachrichten-Definitionen, Erweiterungsanweisungen, Erweiterungen, Gruppen, Optionen, Oneofs, Map-Felder und reservierte Anweisungen enthalten. Eine Nachricht kann nicht zwei Felder mit demselben Namen im selben Nachrichtenschema enthalten.
message = "message" messageName messageBody
messageBody = "{" { field | enum | message | extend | extensions | group |
option | oneof | mapField | reserved | emptyStatement } "}"
Beispiel
message Outer {
option (my_option).a = true;
message Inner { // Level 2
required int64 ival = 1;
}
map<int32, string> my_map = 2;
extensions 20 to 30;
}
Keine der innerhalb einer Nachricht deklarierten Entitäten darf widersprüchliche Namen haben. Alle folgenden sind verboten
message MyMessage {
string foo = 1;
message foo {}
}
message MyMessage {
string foo = 1;
oneof foo {
string bar = 2;
}
}
message MyMessage {
string foo = 1;
extend Extendable {
string foo = 2;
}
}
message MyMessage {
string foo = 1;
enum E {
foo = 0;
}
}
Erweitern
Wenn eine Nachricht in derselben oder einer importierten .proto-Datei einen Bereich für Erweiterungen reserviert hat, kann die Nachricht erweitert werden.
extend = "extend" messageType "{" {field | group} "}"
Beispiel
extend Foo {
int32 bar = 126;
}
Dienstdefinition
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 | extend | service
Ein Beispiel .proto-Datei
edition = "2023";
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 [features.field_presence = LEGACY_REQUIRED];
}
repeated Inner inner_message = 2;
EnumAllowingAlias enum_field = 3;
map<int32, string> my_map = 4;
extensions 20 to 30;
reserved reserved_field;
}
message Foo {
message GroupMessage {
bool a = 1;
}
GroupMessage groupmessage = [features.message_encoding = DELIMITED];
}