Protobuf Editionen Übersicht
Protobuf Editionen ersetzen die Bezeichnungen proto2 und proto3, die wir für Protocol Buffers verwendet haben. Anstatt syntax = "proto2" oder syntax = "proto3" am Anfang von Proto-Definitionsdateien zu verwenden, nutzen Sie eine Editionsnummer, z. B. edition = "2024", um die Standardverhalten anzugeben, die Ihre Datei haben wird. Editionen ermöglichen es der Sprache, sich schrittweise weiterzuentwickeln.
Anstelle von fest kodierten Verhaltensweisen älterer Versionen stellen Editionen eine Sammlung von Features mit einem Standardwert (Verhalten) pro Feature dar. Features sind Optionen für eine Datei, eine Nachricht, ein Feld, eine Aufzählung usw., die das Verhalten von protoc, den Code-Generatoren und den Protobuf-Laufzeitumgebungen festlegen. Sie können ein Verhalten auf diesen verschiedenen Ebenen (Datei, Nachricht, Feld, ...) explizit überschreiben, wenn Ihre Anforderungen nicht dem Standardverhalten der von Ihnen ausgewählten Edition entsprechen. Sie können Ihre Überschreibungen auch überschreiben. Der Abschnitt weiter unten in diesem Thema über lexikalisches Scoping geht näher darauf ein.
HINWEIS: Die neueste veröffentlichte Edition ist 2024.
Lebenszyklus eines Features
Editionen bieten die grundlegenden Inkremente für den Lebenszyklus eines Features. Features haben einen erwarteten Lebenszyklus: Einführung, Änderung des Standardverhaltens, Einstellung und dann Entfernung. Zum Beispiel:
Edition 2031 erstellt
feature.amazing_new_featuremit dem Standardwertfalse. Dieser Wert behält dasselbe Verhalten wie alle früheren Editionen bei. Das heißt, er steht standardmäßig für keine Auswirkung. Nicht alle neuen Features stehen standardmäßig für die No-Op-Option zur Verfügung, aber der Einfachheit halber tut diesamazing_new_feature.Entwickler aktualisieren ihre .proto-Dateien auf
edition = "2031".Eine spätere Edition, wie z. B. Edition 2033, ändert den Standardwert von
feature.amazing_new_featurevonfalseauftrue. Dies ist das gewünschte Verhalten für alle protos und der Grund, warum das Protobuf-Team das Feature entwickelt hat.Durch die Verwendung des Prototiller-Tools zur Migration früherer Proto-Dateiversionen auf Edition 2033 werden bei Bedarf explizite Einträge
feature.amazing_new_feature = falsehinzugefügt, um das vorherige Verhalten beizubehalten. Entwickler entfernen diese neu hinzugefügten Einstellungen, wenn sie möchten, dass das neue Verhalten auf ihre .proto-Dateien angewendet wird.
Zu einem bestimmten Zeitpunkt wird
feature.amazing_new_featurein einer Edition als veraltet markiert und in einer späteren Edition entfernt.Wenn ein Feature entfernt wird, können die Code-Generatoren für dieses Verhalten und die unterstützenden Laufzeitbibliotheken ebenfalls entfernt werden. Die Zeitpläne werden jedoch großzügig sein. Nach dem Beispiel in den vorherigen Schritten des Lebenszyklus kann die Veraltung in Edition 2034 erfolgen, aber erst in Edition 2036 entfernt werden, also etwa zwei Jahre später. Die Entfernung eines Features wird immer eine Hauptversionsnummerierung auslösen.
Sie haben das volle Zeitfenster der Google-Migration zuzüglich des Veraltungsfensters, um Ihren Code zu aktualisieren.
Das vorherige Lebenszyklusbeispiel verwendete boolesche Werte für die Features, aber Features können auch Aufzählungen verwenden. Zum Beispiel hat features.field_presence die Werte LEGACY_REQUIRED, EXPLICIT und IMPLICIT.
Migration zu Protobuf Editionen
Editionen brechen keine vorhandenen Binärdateien und ändern nicht das binäre, textbasierte oder JSON-Serialisierungsformat einer Nachricht. Edition 2023 war so wenig störend wie möglich. Sie etablierte die Basislinie und kombinierte proto2- und proto3-Definitionen in einem neuen, einheitlichen Definitionsformat.
Mit der Veröffentlichung weiterer Editionen können sich Standardverhalten für Features ändern. Sie können Prototiller eine Nulloperationstransformation Ihrer .proto-Datei durchführen lassen oder Sie können sich dafür entscheiden, einige oder alle neuen Verhaltensweisen zu übernehmen. Editionen werden voraussichtlich etwa einmal im Jahr veröffentlicht.
Proto2 zu Editionen
Dieser Abschnitt zeigt eine proto2-Datei und wie sie nach der Ausführung des Prototiller-Tools zur Änderung der Definitionsdateien zur Verwendung der Protobuf Editions-Syntax aussehen könnte.
Proto2-Syntax
// proto2 file
syntax = "proto2";
package com.example;
message Player {
// in proto2, optional fields have explicit presence
optional string name = 1 [default = "N/A"];
// proto2 still supports the problematic "required" field rule
required int32 id = 2;
// in proto2 this is not packed by default
repeated int32 scores = 3;
enum Handed {
HANDED_UNSPECIFIED = 0;
HANDED_LEFT = 1;
HANDED_RIGHT = 2;
HANDED_AMBIDEXTROUS = 3;
}
// in proto2 enums are closed
optional Handed handed = 4;
reserved "gender";
}
Editions-Syntax
// Edition version of proto2 file
edition = "2024";
package com.example;
option features.utf8_validation = NONE;
option features.enforce_naming_style = STYLE_LEGACY;
option features.default_symbol_visibility = EXPORT_ALL;
// Sets the default behavior for C++ strings
option features.(pb.cpp).string_type = STRING;
message Player {
// fields have explicit presence, so no explicit setting needed
string name = 1 [default = "N/A"];
// to match the proto2 behavior, LEGACY_REQUIRED is set at the field level
int32 id = 2 [features.field_presence = LEGACY_REQUIRED];
// to match the proto2 behavior, EXPANDED is set at the field level
repeated int32 scores = 3 [features.repeated_field_encoding = EXPANDED];
export enum Handed {
// this overrides the default editions behavior, which is OPEN
option features.enum_type = CLOSED;
HANDED_UNSPECIFIED = 0;
HANDED_LEFT = 1;
HANDED_RIGHT = 2;
HANDED_AMBIDEXTROUS = 3;
}
Handed handed = 4;
reserved gender;
}
Proto3 zu Editionen
Dieser Abschnitt zeigt eine proto3-Datei und wie sie nach der Ausführung des Prototiller-Tools zur Änderung der Definitionsdateien zur Verwendung der Protobuf Editions-Syntax aussehen könnte.
Proto3-Syntax
// proto3 file
syntax = "proto3";
package com.example;
message Player {
// in proto3, optional fields have explicit presence
optional string name = 1;
// in proto3 no specified field rule defaults to implicit presence
int32 id = 2;
// in proto3 this is packed by default
repeated int32 scores = 3;
enum Handed {
HANDED_UNSPECIFIED = 0;
HANDED_LEFT = 1;
HANDED_RIGHT = 2;
HANDED_AMBIDEXTROUS = 3;
}
// in proto3 enums are open
optional Handed handed = 4;
reserved "gender";
}
Editions-Syntax
// Editions version of proto3 file
edition = "2024";
package com.example;
option features.utf8_validation = NONE;
option features.enforce_naming_style = STYLE_LEGACY;
option features.default_symbol_visibility = EXPORT_ALL;
// Sets the default behavior for C++ strings
option features.(pb.cpp).string_type = STRING;
message Player {
// fields have explicit presence, so no explicit setting needed
string name = 1 [default = "N/A"];
// to match the proto3 behavior, IMPLICIT is set at the field level
int32 id = 2 [features.field_presence = IMPLICIT];
// PACKED is the default state, and is provided just for illustration
repeated int32 scores = 3 [features.repeated_field_encoding = PACKED];
export enum Handed {
HANDED_UNSPECIFIED = 0;
HANDED_LEFT = 1;
HANDED_RIGHT = 2;
HANDED_AMBIDEXTROUS = 3;
}
Handed handed = 4;
reserved gender;
}
Lexikalisches Scoping
Die Editions-Syntax unterstützt lexikalisches Scoping mit einer pro-Feature-Liste zulässiger Ziele. Zum Beispiel können in Edition 2023 Features nur auf Dateiebene oder auf der niedrigsten Granularitätsebene angegeben werden. Die Implementierung von lexikalischem Scoping ermöglicht es Ihnen, das Standardverhalten für ein Feature über eine gesamte Datei festzulegen und dieses Verhalten dann auf Nachricht-, Feld-, Aufzählungs-, Aufzählungswert-, Oneof-, Service- oder Methodenebene zu überschreiben. Einstellungen, die auf einer höheren Ebene (Datei, Nachricht) vorgenommen werden, gelten, wenn keine Einstellung im selben Geltungsbereich (Feld, Aufzählungswert) vorgenommen wird. Nicht explizit gesetzte Features entsprechen dem in der für die .proto-Datei verwendeten Edition definierten Verhalten.
Das folgende Codebeispiel zeigt einige Features, die auf Datei-, Feld- und Aufzählungsebene gesetzt werden.
edition = "2024";
option features.enum_type = CLOSED;
message Person {
string name = 1;
int32 id = 2 [features.field_presence = IMPLICIT];
enum Pay_Type {
PAY_TYPE_UNSPECIFIED = 1;
PAY_TYPE_SALARY = 2;
PAY_TYPE_HOURLY = 3;
}
enum Employment {
option features.enum_type = OPEN;
EMPLOYMENT_UNSPECIFIED = 0;
EMPLOYMENT_FULLTIME = 1;
EMPLOYMENT_PARTTIME = 2;
}
Employment employment = 4;
}
Im vorherigen Beispiel ist das Präsenzfeature auf IMPLICIT gesetzt; es würde standardmäßig auf EXPLICIT gesetzt werden, wenn es nicht gesetzt wäre. Die Pay_Type enum wird CLOSED sein, da sie die Einstellung auf Dateiebene anwendet. Die Employment enum wird jedoch OPEN sein, da sie innerhalb der Aufzählung gesetzt ist.
Prototiller
Wenn das Prototiller-Tool gestartet wird, stellen wir sowohl eine Migrationsanleitung als auch Migrationswerkzeuge zur Verfügung, um die Migration zu und zwischen Editionen zu erleichtern. Das Tool ermöglicht Ihnen:
- Konvertierung von proto2- und proto3-Definitionsdateien in die neue Editions-Syntax, im großen Stil
- Migration von Dateien von einer Edition zu einer anderen
- Manipulation von Proto-Dateien auf andere Weise
Abwärtskompatibilität
Wir entwickeln Protobuf Editionen so, dass sie so wenig störend wie möglich sind. Sie können beispielsweise proto2- und proto3-Definitionen in editionsbasierte Definitionsdateien importieren und umgekehrt.
// file myproject/foo.proto
syntax = "proto2";
enum Employment {
EMPLOYMENT_UNSPECIFIED = 0;
EMPLOYMENT_FULLTIME = 1;
EMPLOYMENT_PARTTIME = 2;
}
// file myproject/edition.proto
edition = "2024";
import "myproject/foo.proto";
Obwohl sich der generierte Code bei der Umstellung von proto2 oder proto3 auf Editionen ändert, ändert sich das Wire-Format nicht. Sie können weiterhin auf proto2- und proto3-Datendateien oder Dateistreams mit Ihren Protobuf-Definitionen in Editions-Syntax zugreifen.
Grammatikänderungen
Es gibt einige Grammatikänderungen in Editionen im Vergleich zu proto2 und proto3.
Syntaxbeschreibung
Anstelle des Elements syntax verwenden Sie ein Element edition.
syntax = "proto2";
syntax = "proto3";
edition = "2028";
Reservierte Namen
Sie setzen Feldnamen und Aufzählungswerternamen nicht mehr in Anführungszeichen, wenn Sie sie reservieren.
reserved foo, bar;
Gruppensyntax
Die Gruppensyntax, die in proto2 verfügbar war, wird in Editionen entfernt. Das spezielle Wire-Format, das Gruppen verwendeten, ist weiterhin durch die Verwendung der DELIMITED Nachrichtenverschlüsselung verfügbar.
required-Label
Das required-Label, das nur in proto2 verfügbar war, ist in Editionen nicht verfügbar. Die zugrunde liegende Funktionalität ist weiterhin durch die Verwendung von features.field_presence=LEGACY_REQUIRED verfügbar.
import option
Edition 2024 fügte Unterstützung für Option-Importe mit der Syntax import option hinzu.
Option-Importe müssen nach allen anderen import-Anweisungen erfolgen.
Im Gegensatz zu normalen import-Anweisungen importiert import option nur benutzerdefinierte Optionen, die in einer .proto-Datei definiert sind, ohne andere Symbole zu importieren.
Das bedeutet, dass Nachrichten und Aufzählungen vom Optionsimport ausgeschlossen sind. Im folgenden Beispiel kann die Bar-Nachricht nicht als Feldtyp in foo.proto verwendet werden, aber Optionen vom Typ Bar können weiterhin gesetzt werden.
// bar.proto
edition = "2024";
import "google/protobuf/descriptor.proto";
message Bar {
bool bar = 1;
}
extend proto2.FileOptions {
bool file_opt1 = 5000;
Bar file_opt2 = 5001;
}
// foo.proto:
edition = "2024";
import option "bar.proto";
option (file_opt1) = true;
option (file_opt2) = {bar: true};
message Foo {
// Bar bar = 1; // This is not allowed
}
Optionsimporte benötigen keinen generierten Code für ihre Symbole und sollten daher als option_deps in proto_library anstelle von deps bereitgestellt werden. Dadurch wird die Generierung von nicht erreichbarem Code vermieden.
proto_library(
name = "foo",
srcs = ["foo.proto"],
option_deps = [":custom_option_proto"]
)
Optionsimporte und option_deps werden dringend empfohlen, wenn Protobuf-Sprachfeatures und andere benutzerdefinierte Optionen importiert werden, um die Generierung von unnötigem Code zu vermeiden.
Dies ersetzt import weak, das in Edition 2024 entfernt wurde.
export / local Schlüsselwörter
export- und local-Schlüsselwörter wurden in Edition 2024 als Modifikatoren für die Symbol-Sichtbarkeit von importierbaren Symbolen hinzugefügt, vom Standardverhalten, das durch features.default_symbol_visibility angegeben wird.
Dies steuert, welche Symbole aus anderen Proto-Dateien importiert werden können, wirkt sich aber nicht auf die Code-Generierung aus.
In Edition 2024 können diese standardmäßig für alle message- und enum-Symbole festgelegt werden. Einige Werte des Features default_symbol_visibility schränken jedoch weiter ein, welche Symbole exportierbar sind.
Beispiel
// Top-level symbols are exported by default in Edition 2024
message LocalMessage {
int32 baz = 1;
// Nested symbols are local by default in Edition 2024; applying the `export`
// keyword overrides this
export enum ExportedNestedEnum {
UNKNOWN_EXPORTED_NESTED_ENUM_VALUE = 0;
}
}
// The `local` keyword overrides the default behavior of exporting messages
local message AnotherMessage {
int32 foo = 1;
}
import weak und Weak Field Option
Ab Edition 2024 sind schwache Importe nicht mehr zulässig.
Wenn Sie zuvor import weak verwendet haben, um eine "schwache Abhängigkeit" zu deklarieren – um benutzerdefinierte Optionen ohne generierten Code für C++ und Go zu importieren – sollten Sie stattdessen auf import option migrieren.
Weitere Details finden Sie unter import option.
ctype Field Option
Ab Edition 2024 ist die ctype-Feldoption nicht mehr zulässig. Verwenden Sie stattdessen das string_type-Feature.
Weitere Details finden Sie unter features.(pb.cpp).string_type.
java_multiple_files File Option
Ab Edition 2024 ist die java_multiple_files-Dateioption nicht mehr verfügbar. Verwenden Sie stattdessen das Java-Feature features.(pb.java).nest_in_file_class.