版本的功能設定
本主題概述了 2023 版本中包含的功能。每個後續版本的功能都將新增至本主題。我們會在新聞區公布新版本。
Prototiller
Prototiller 是一個命令列工具,可將 proto2 和 proto3 定義檔案轉換為版本語法。它尚未發布,但在本主題中會被引用。
功能
以下章節包含所有可使用 2023 版本的功能配置的行為。保留 proto2 或 proto3 行為說明如何覆寫預設行為,使您的 proto 定義檔案的行為如同 proto2 或 proto3 檔案。如需版本和功能如何協同運作以設定行為的詳細資訊,請參閱Protobuf 版本概觀。
以下每個章節都有一個項目,說明該功能適用的範圍。這可以包括檔案、列舉、訊息或欄位。以下範例顯示套用至每個範圍的模擬功能
edition = "2023";
// File-scope definition
option features.bar = BAZ;
enum Foo {
// Enum-scope definition
option features.bar = QUX;
A = 1;
B = 2;
}
message Corge {
// Message-scope definition
option features.bar = QUUX;
// Field-scope definition
Foo A = 1 [features.bar = GRAULT];
}
在此範例中,欄位範圍功能定義中的設定 GRAULT
會覆寫訊息範圍的 QUUX 設定。
features.enum_type
此功能設定如何處理未包含在已定義集合中的列舉值的行為。如需關於開放和封閉列舉的詳細資訊,請參閱列舉行為。
此功能不會影響 proto3 檔案,因此本節沒有 proto3 檔案的前後對照。
可用值
CLOSED:
封閉列舉會將範圍外的列舉值儲存在未知欄位集合中。OPEN:
開放列舉會將範圍外的值直接剖析到其欄位中。
適用於以下範圍: 檔案、列舉
2023 版本中的預設行為: OPEN
在 proto2 中的行為: CLOSED
在 proto3 中的行為: OPEN
以下程式碼範例顯示一個 proto2 檔案
syntax = "proto2";
enum Foo {
A = 2;
B = 4;
C = 6;
}
執行Prototiller之後,等效的程式碼可能如下所示
edition = "2023";
enum Foo {
option features.enum_type = CLOSED;
A = 2;
B = 4;
C = 6;
}
features.field_presence
此功能設定追蹤欄位存在性或 protobuf 欄位是否有值的概念的行為。
可用值
LEGACY_REQUIRED
:欄位是剖析和序列化所必需的。任何明確設定的值都會序列化到線路上 (即使它與預設值相同)。EXPLICIT
:欄位具有明確的存在性追蹤。任何明確設定的值都會序列化到線路上 (即使它與預設值相同)。對於單數基本欄位,會為設定為EXPLICIT
的欄位產生has_*
函式。IMPLICIT
:欄位沒有存在性追蹤。預設值不會序列化到線路上 (即使它是明確設定的)。不會為設定為IMPLICIT
的欄位產生has_*
函式。
適用於以下範圍: 檔案、欄位
2023 版本中的預設值: EXPLICIT
在 proto2 中的行為: EXPLICIT
在 proto3 中的行為: IMPLICIT
,除非欄位具有 optional
標籤,在這種情況下,它的行為會如同 EXPLICIT
。如需詳細資訊,請參閱Proto3 API 中的存在性。
以下程式碼範例顯示一個 proto2 檔案
syntax = "proto2";
message Foo {
required int32 x = 1;
optional int32 y = 2;
repeated int32 z = 3;
}
執行 Prototiller 之後,等效的程式碼可能如下所示
edition = "2023";
message Foo {
int32 x = 1 [features.field_presence = LEGACY_REQUIRED];
int32 y = 2;
repeated int32 z = 3;
}
以下顯示一個 proto3 檔案
syntax = "proto3";
message Bar {
int32 x = 1;
optional int32 y = 2;
repeated int32 z = 3;
}
執行 Prototiller 之後,等效的程式碼可能如下所示
edition = "2023";
option features.field_presence = IMPLICIT;
message Bar {
int32 x = 1;
int32 y = 2 [features.field_presence = EXPLICIT];
repeated int32 z = 3;
}
請注意,required
和 optional
標籤在版本中已不再存在,因為對應的行為是使用 field_presence
功能明確設定的。
features.json_format
此功能設定 JSON 剖析和序列化的行為。
此功能不會影響 proto3 檔案,因此本節沒有 proto3 檔案的前後對照。版本行為與 proto3 中的行為一致。
可用值
ALLOW
:執行階段必須允許 JSON 剖析和序列化。在 proto 層級套用檢查,以確保與 JSON 有明確定義的對應。LEGACY_BEST_EFFORT
:執行階段會盡力剖析和序列化 JSON。允許某些 proto,這些 proto 可能會在執行階段產生未指定的行為 (例如 many:1 或 1:many 對應)。
適用於以下範圍: 檔案、訊息、列舉
2023 版本中的預設行為: ALLOW
在 proto2 中的行為: LEGACY_BEST_EFFORT
在 proto3 中的行為: ALLOW
以下程式碼範例顯示一個 proto2 檔案
syntax = "proto2";
message Foo {
// Warning only
string bar = 1;
string bar_ = 2;
}
執行 Prototiller 之後,等效的程式碼可能如下所示
edition = "2023";
features.json_format = LEGACY_BEST_EFFORT;
message Foo {
string bar = 1;
string bar_ = 2;
}
features.message_encoding
此功能設定序列化時編碼欄位的行為。
此功能不會影響 proto3 檔案,因此本節沒有 proto3 檔案的前後對照。
根據語言,為了提供與 proto2 的回溯相容性,在產生的程式碼和文字格式中,屬於「群組類型」的欄位可能會有一些非預期的首字母大寫。如果符合以下所有條件,訊息欄位會是「群組類型」
- 已指定
DELIMITED
訊息編碼 - 訊息類型與欄位定義在相同的範圍中
- 欄位名稱與小寫的類型名稱完全相同
可用值
適用於以下範圍: 檔案、欄位
2023 版本中的預設行為: LENGTH_PREFIXED
在 proto2 中的行為: 除了群組預設為 DELIMITED
之外,皆為 LENGTH_PREFIXED
在 proto3 中的行為: LENGTH_PREFIXED
。Proto3 不支援 DELIMITED
。
以下程式碼範例顯示一個 proto2 檔案
syntax = "proto2";
message Foo {
group Bar = 1 {
optional int32 x = 1;
repeated int32 y = 2;
}
}
執行 Prototiller 之後,等效的程式碼可能如下所示
edition = "2023";
message Foo {
message Bar {
int32 x = 1;
repeated int32 y = 2;
}
Bar bar = 1 [features.message_encoding = DELIMITED];
}
features.repeated_field_encoding
此功能是 proto2/proto3 packed
選項在版本中已移轉至的功能。
可用值
PACKED
:基本類型的Repeated
欄位會編碼為單一 LEN 記錄,其中包含每個串聯的元素。EXPANDED
:Repeated
欄位會針對每個值使用欄位編號進行編碼。
適用於以下範圍: 檔案、欄位
2023 版本中的預設行為: PACKED
在 proto2 中的行為: EXPANDED
在 proto3 中的行為: PACKED
以下程式碼範例顯示一個 proto2 檔案
syntax = "proto2";
message Foo {
repeated int32 bar = 6 [packed=true];
repeated int32 baz = 7;
}
執行 Prototiller 之後,等效的程式碼可能如下所示
edition = "2023";
option features.repeated_field_encoding = EXPANDED;
message Foo {
repeated int32 bar = 6 [features.repeated_field_encoding=PACKED];
repeated int32 baz = 7;
}
以下顯示一個 proto3 檔案
syntax = "proto3";
message Foo {
repeated int32 bar = 6;
repeated int32 baz = 7 [packed=false];
}
執行 Prototiller 之後,等效的程式碼可能如下所示
edition = "2023";
message Foo {
repeated int32 bar = 6;
repeated int32 baz = 7 [features.repeated_field_encoding=EXPANDED];
}
features.utf8_validation
此功能設定如何驗證字串。它適用於所有語言,除非有覆寫它的特定語言 utf8_validation
功能。如需 Java 特定語言的功能,請參閱features.(pb.java).utf8_validation
。
此功能不會影響 proto3 檔案,因此本節沒有 proto3 檔案的前後對照。
可用值
VERIFY
:執行階段應驗證 UTF-8。這是預設的 proto3 行為。NONE
:欄位的行為如同線路上未驗證的bytes
欄位。剖析器可能會以無法預測的方式處理此類型的欄位,例如取代無效的字元。這是預設的 proto2 行為。
適用於以下範圍: 檔案、欄位
2023 版本中的預設行為: VERIFY
在 proto2 中的行為: NONE
在 proto3 中的行為: VERIFY
以下程式碼範例顯示一個 proto2 檔案
syntax = "proto2";
message MyMessage {
string foo = 1;
}
執行 Prototiller 之後,等效的程式碼可能如下所示
edition = "2023";
message MyMessage {
string foo = 1 [features.utf8_validation = NONE];
}
特定語言的功能
某些功能適用於特定語言,而不適用於其他語言中的相同 proto。使用這些功能需要您從語言的執行階段匯入對應的 *_features.proto 檔案。以下章節中的範例會顯示這些匯入。
features.(pb.cpp/pb.java).legacy_closed_enum
語言: C++、Java
此功能決定具有開放列舉類型的欄位是否應該像封閉列舉一樣運作。這允許版本在 Java 和 C++ 中重現來自 proto2 和 proto3 的不一致的行為。
此功能不會影響 proto3 檔案,因此本節沒有 proto3 檔案的前後對照。
可用值
true
:不論enum_type
中設定的值為何,都將列舉視為封閉。false
:遵循enum_type
中設定的任何值。
適用於以下範圍: 檔案、欄位
2023 版本中的預設行為: false
在 proto2 中的行為: true
在 proto3 中的行為: false
以下程式碼範例顯示一個 proto2 檔案
syntax = "proto2";
import "myproject/proto3file.proto";
message Msg {
myproject.proto3file.Proto3Enum name = 1;
}
執行 Prototiller 之後,等效的程式碼可能如下所示
edition = "2023";
import "myproject/proto3file.proto";
import "google/protobuf/cpp_features.proto";
import "google/protobuf/java_features.proto";
message Msg {
myproject.proto3file.Proto3Enum name = 1 [
features.(pb.cpp).legacy_closed_enum = true,
features.(pb.java).legacy_closed_enum = true
];
}
features.(pb.cpp).string_type
語言: C++
此功能決定產生的程式碼應如何處理字串欄位。這會取代 proto2 和 proto3 中的 ctype
選項,並提供新的 string_view
功能。在 2023 版本中,可以在欄位上指定 ctype
或 string_view
,但不能同時指定兩者。
可用值
VIEW
:為欄位產生string_view
存取子。這將是未來版本的預設值。CORD
:為欄位產生Cord
存取子。STRING
:為欄位產生string
存取子。
適用於以下範圍: 檔案、欄位
2023 版本中的預設行為: STRING
在 proto2 中的行為: STRING
在 proto3 中的行為: STRING
以下程式碼範例顯示一個 proto2 檔案
syntax = "proto2";
message Foo {
optional string bar = 6;
optional string baz = 7 [ctype = CORD];
}
執行 Prototiller 之後,等效的程式碼可能如下所示
edition = "2023";
import "google/protobuf/cpp_features.proto";
message Foo {
string bar = 6;
string baz = 7 [features.(pb.cpp).string_type = CORD];
}
以下顯示一個 proto3 檔案
syntax = "proto3"
message Foo {
string bar = 6;
string baz = 7 [ctype = CORD];
}
執行 Prototiller 之後,等效的程式碼可能如下所示
edition = "2023";
import "google/protobuf/cpp_features.proto";
message Foo {
string bar = 6;
string baz = 7 [features.(pb.cpp).string_type = CORD];
}
features.(pb.java).utf8_validation
語言: Java
此特定語言功能可讓您僅針對 Java 覆寫欄位層級的檔案層級設定。
此功能不會影響 proto3 檔案,因此本節沒有 proto3 檔案的前後對照。
可用值
DEFAULT
:此行為會符合features.utf8_validation
所設定的行為。VERIFY
:覆寫檔案層級的features.utf8_validation
設定,強制僅針對 Java 設定為VERIFY
。
適用範圍: 欄位、檔案
2023 版本中的預設行為:DEFAULT
在 proto2 中的行為:DEFAULT
在 proto3 中的行為:DEFAULT
以下程式碼範例顯示一個 proto2 檔案
syntax = "proto2";
option java_string_check_utf8=true;
message MyMessage {
string foo = 1;
string bar = 2;
}
執行 Prototiller 之後,等效的程式碼可能如下所示
edition = "2023";
import "google/protobuf/java_features.proto";
option features.utf8_validation = NONE;
option features.(pb.java).utf8_validation = VERIFY;
message MyMessage {
string foo = 1;
}
保留 proto2 或 proto3 行為
您可能想要轉換至版本格式,但不處理產生程式碼行為的更新。此章節將說明 Prototiller 工具對您的 .proto 檔案所做的變更,以使 2023 版本的 proto 行為如同 proto2 或 proto3 檔案。
在檔案層級進行這些變更後,您會獲得 proto2 或 proto3 的預設值。您可以在較低的層級(訊息層級、欄位層級)覆寫,以考慮額外的行為差異(例如 required、proto3 optional),或者如果您的定義只想大致如同 proto2 或 proto3。
除非您有不使用的特定原因,否則我們建議使用 Prototiller。若要手動套用所有這些設定而不是使用 Prototiller,請將以下章節的內容新增至 .proto 檔案的頂端。
Proto2 行為
edition = "2023";
import "google/protobuf/cpp_features.proto";
import "google/protobuf/java_features.proto";
option features.field_presence = EXPLICIT;
option features.enum_type = CLOSED;
option features.repeated_field_encoding = EXPANDED;
option features.json_format = LEGACY_BEST_EFFORT;
option features.utf8_validation = NONE;
option features.(pb.cpp).legacy_closed_enum = true;
option features.(pb.java).legacy_closed_enum = true;
Proto3 行為
// proto3 behaviors
edition = "2023";
import "google/protobuf/cpp_features.proto";
import "google/protobuf/java_features.proto";
option features.field_presence = IMPLICIT;
option features.enum_type = OPEN;
// `packed=false` needs to be transformed to field-level repeated_field_encoding
// features in Editions syntax
option features.json_format = ALLOW;
option features.utf8_validation = VERIFY;
option features.(pb.cpp).legacy_closed_enum = false;
option features.(pb.java).legacy_closed_enum = false;
注意事項和例外
本章節說明如果您選擇不使用 Prototiller,需要手動進行的變更。
設定上一節中顯示的檔案層級預設值可在大多數情況下設定預設行為,但有一些例外情況。
optional
:移除所有optional
標籤的實例,如果檔案預設值為IMPLICIT
,則將features.field_presence
變更為EXPLICIT
。required
:移除所有required
標籤的實例,並在欄位層級新增features.field_presence=LEGACY_REQUIRED
選項。groups
:將groups
解包成一個獨立的訊息,並在欄位層級新增features.message_encoding = DELIMITED
選項。請參閱features.message_encoding
以瞭解更多資訊。java_string_check_utf8
:移除此檔案選項,並以features.(pb.java).utf8_validation
取代。您需要匯入 Java 功能,如語言特定功能所述。packed
:對於轉換為版本格式的 proto2 檔案,移除packed
欄位選項,並且當您不希望 Proto2 行為中設定的EXPANDED
行為時,請在欄位層級新增[features.repeated_field_encoding=PACKED]
。對於轉換為版本格式的 proto3 檔案,當您不想要預設的 proto3 行為時,請在欄位層級新增[features.repeated_field_encoding=EXPANDED]
。