Protobuf 版本概觀
Protobuf 版本取代了我們用於 Protocol Buffers 的 proto2 和 proto3 指定。您不再需要在 proto 定義檔案頂端新增 syntax = "proto2"
或 syntax = "proto3"
,而是使用版本號碼 (例如 edition = "2023"
) 來指定檔案將擁有的預設行為。版本讓語言能夠隨著時間逐步演進。
版本不是舊版本擁有的硬式編碼行為,而是代表一組特性,每個特性都有預設值 (行為)。特性是檔案、訊息、欄位、列舉等選項,用於指定 protoc、程式碼產生器和 protobuf 執行階段的行為。當您的需求與您選取的版本預設行為不符時,您可以明確覆寫這些不同層級 (檔案、訊息、欄位…) 的行為。您也可以覆寫您的覆寫。本主題稍後關於詞法範圍的章節將更詳細地說明。
最新發布的版本是 2023。
特性的生命週期
版本為特性的生命週期提供基本增量。特性具有預期的生命週期:導入、變更預設行為、棄用,然後移除。例如:
版本 2031 建立
feature.amazing_new_feature
,預設值為false
。此值維持與所有先前版本相同的行為。也就是說,預設為無影響。開發人員將其 .proto 檔案更新為
edition = "2031"
。稍後版本 (例如版本 2033) 將
feature.amazing_new_feature
的預設值從false
切換為true
。這是所有 proto 的所需行為,也是 protobuf 團隊建立此特性的原因。使用 Prototiller 工具將舊版 proto 檔案遷移至版本 2033,會視需要新增明確的
feature.amazing_new_feature = false
項目,以繼續保留先前的行為。當開發人員希望新行為套用至其 .proto 檔案時,可以移除這些新增加的設定。
在某個時間點,
feature.amazing_new_feature
會在某個版本中標記為已棄用,並在稍後版本中移除。移除特性後,該行為的程式碼產生器和支援它的執行階段程式庫也可能會被移除。但時程將會寬裕。以下列生命週期先前步驟中的範例來說,棄用可能會在版本 2034 中發生,但直到版本 2036 才移除,大約在兩年後。移除特性將始終啟動主要版本升級。
由於此生命週期,任何未使用已棄用特性的 .proto
檔案,從一個版本升級到下一個版本都是無作業升級。您將擁有 Google 遷移的完整窗口,以及棄用窗口來升級您的程式碼。
先前的生命週期範例使用布林值作為特性,但特性也可以使用列舉。例如,features.field_presence
具有值 LEGACY_REQUIRED
、EXPLICIT
和 IMPLICIT
。
遷移至 Protobuf 版本
版本不會破壞現有二進位檔,也不會變更訊息的二進位、文字或 JSON 序列化格式。第一個版本盡可能地減少破壞性。第一個版本建立了基準,並將 proto2 和 proto3 定義合併為新的單一定義格式。
當後續版本發布時,特性的預設行為可能會變更。您可以讓 Prototiller 對您的 .proto 檔案執行無作業轉換,或者您可以選擇接受部分或全部新行為。版本計劃大約每年發布一次。
Proto2 至版本
本節顯示 proto2 檔案,以及執行 Prototiller 工具以將定義檔案變更為使用 Protobuf 版本語法後的外觀。
Proto2 語法
// 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";
}
版本語法
// Edition version of proto2 file
edition = "2023";
package com.example;
option features.utf8_validation = NONE;
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];
enum Handed {
// this overrides the default edition 2023 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 至版本
本節顯示 proto3 檔案,以及執行 Prototiller 工具以將定義檔案變更為使用 Protobuf 版本語法後的外觀。
Proto3 語法
// proto3 file
syntax = "proto3";
package com.example;
message Player {
// in proto3, optional fields have explicit presence
optional string name = 1 [default = "N/A"];
// 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 version of proto3 file
edition = "2023";
package com.example;
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];
enum Handed {
HANDED_UNSPECIFIED = 0;
HANDED_LEFT = 1;
HANDED_RIGHT = 2;
HANDED_AMBIDEXTROUS = 3;
}
Handed handed = 4;
reserved gender;
}
詞法範圍
版本語法支援詞法範圍,以及每個特性的允許目標清單。例如,在第一個版本中,特性只能在檔案層級或最細微的層級指定。詞法範圍的實作讓您可以為整個檔案的特性設定預設行為,然後在訊息、欄位、列舉、列舉值、oneof、服務或方法層級覆寫該行為。在較高層級 (檔案、訊息) 進行的設定,會在相同範圍 (欄位、列舉值) 內未進行設定時套用。任何未明確設定的特性都符合 .proto 檔案所用版本中定義的行為。
以下程式碼範例顯示在檔案、欄位和列舉層級設定的一些特性。
edition = "2023";
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;
}
在先前的範例中,存在性特性設定為 IMPLICIT
;如果未設定,則預設為 EXPLICIT
。Pay_Type
enum
將為 CLOSED
,因為它套用檔案層級設定。但是,Employment
enum
將為 OPEN
,因為它是在列舉內設定的。
Prototiller
當 Prototiller 工具啟動時,我們將提供遷移指南和遷移工具,以簡化遷移至版本以及版本之間的遷移。此工具將讓您能夠:
- 大規模地將 proto2 和 proto3 定義檔案轉換為新的版本語法
- 將檔案從一個版本遷移到另一個版本
- 以其他方式操作 proto 檔案
回溯相容性
我們正在建構 Protobuf 版本,以盡可能減少破壞性。例如,您可以將 proto2 和 proto3 定義匯入至基於版本的定義檔案,反之亦然
// file myproject/foo.proto
syntax = "proto2";
enum Employment {
EMPLOYMENT_UNSPECIFIED = 0;
EMPLOYMENT_FULLTIME = 1;
EMPLOYMENT_PARTTIME = 2;
}
// file myproject/edition.proto
edition = "2023";
import "myproject/foo.proto";
雖然從 proto2 或 proto3 移至版本時,產生的程式碼會變更,但線路格式不會變更。您仍然可以使用您的版本語法 proto 定義來存取 proto2 和 proto3 資料檔案或檔案串流。
語法變更
與 proto2 和 proto3 相比,版本中存在一些語法變更。
語法描述。 您不再使用 syntax
元素,而是使用 edition
元素
syntax = "proto2";
syntax = "proto3";
edition = "2028";
保留名稱。 保留欄位名稱和列舉值名稱時,不再將其放在引號中
reserved foo, bar;
群組語法。 版本中移除了 proto2 中可用的群組語法。群組使用的特殊線路格式仍然可以透過使用 DELIMITED
訊息編碼來使用。
required 標籤。 版本中無法使用僅在 proto2 中可用的 required
標籤。底層功能仍然可以透過使用 features.field_presence=LEGACY_REQUIRED
來使用。