版本的功能設定
本主題概述了版本 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 可能導致執行階段發生不明確的行為 (例如多對一或一對多對應)。
適用於以下範圍: 檔案、訊息、列舉
版本 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 中的行為: LENGTH_PREFIXED
,但群組除外,群組預設為 DELIMITED
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
此功能是版本中已遷移的 repeated
欄位之 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
此功能決定具有開放式列舉類型的欄位是否應表現得像封閉式列舉。這讓版本能夠重現 proto2 和 proto3 中 Java 和 C++ 的不相符行為。
此功能不會影響 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_type
,但不能同時指定兩者。
可用值
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;
}
features.(pb.java).large_enum
語言: Java
此語言特定功能可讓您採用可處理 Java 中大型列舉的新功能,而不會造成編譯器錯誤。
這是新行為,因此不會影響 proto2 或 proto3 結構描述定義檔。
可用值
true
:Java 列舉將使用新功能。false
:Java 列舉將繼續使用 Java 列舉。
適用於以下範圍: 列舉
版本 2023 中的預設行為: false
proto2 中的行為: false
proto3 中的行為: false
保留 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
欄位選項,並在欄位層級新增[features.repeated_field_encoding=PACKED]
,當您不想要在Proto2 行為中設定的EXPANDED
行為時。對於轉換為版本格式的 proto3 檔案,當您不想要預設的 proto3 行為時,請在欄位層級新增[features.repeated_field_encoding=EXPANDED]
。