Protobuf3 枚舉
定義消息類型時,您可能希望它的一個字段有一個預定義的值列表。例如,假設您希望為每個SearchRequest添加一個corpus字段,其中語料庫可以是UNIVERSAL、WEB、IMAGES、LOCAL、NEWS、PRODUCTS 或VIDEO。您可以非常簡單地通過在消息定義中添加枚舉來實現這一點,每個可能的值都是一個常量。
在下面的例子中,我們添加了一個名為Corpus 的枚舉和一個類型為Corpus的字段:
message SearchRequest { string query = 1; int32 page_number = 2; int32 result_per_page = 3; enum Corpus { UNIVERSAL = 0; WEB = 1; IMAGES = 2; LOCAL = 3; NEWS = 4; PRODUCTS = 5; VIDEO = 6; } Corpus corpus = 4; }
正如你所看到的,Corpus枚舉的第一個常量映射到0,每個枚舉定義必須包含一個映射到零的常量作為第一個元素。這是因為:
必須有零值,這樣我們就可以使用0作為數值默認值。
零值必須為第一個元素,以便與proto 2語義兼容,其中第一個枚舉值總是默認的。
可以通過為不同的枚舉常量分配相同的值來定義別名。為此,您需要將allow_alias選項設置為true,否則協議編譯器會在找到別名時生成錯誤消息。
enum EnumAllowingAlias { option allow_alias = true; UNKNOWN = 0; STARTED = 1; RUNNING = 1; } enum EnumNotAllowingAlias { UNKNOWN = 0; STARTED = 1; // RUNNING = 1; // Uncommenting this line will cause a compile error inside Google and a warning message outside. }
枚舉數常量必須在32位整數的范圍內。由於enum值在傳輸中使用不同的編碼,負值效率低下,因此不推薦使用。您可以在消息定義中定義枚舉,如上例所示,也可以在消息定義之外定義枚舉——這些枚舉可以在 .proto文件中的消息定義中重用。您也可以使用語法MessageType.EnumType,將一條消息中聲明的枚舉類型用作另一條消息中字段的類型
當你在.proto文件上使用枚舉運行協議緩沖區編譯器時,生成的代碼將具有Java或c++的相應枚舉,Python使用一個EnumDescriptor類,用於在運行時生成的類中創建一組具有整數值的符號常量。
在反序列化期間,無法識別的枚舉值將保留在消息中,盡管反序列化消息時如何表示這些值取決於編程語言。在支持數值超出指定符號范圍的開放式枚舉類型的語言中,例如c++和Go,未知的枚舉值簡單地存儲為其底層整數表示。在具有封閉枚舉類型的語言(如Java)中,在枚舉中無法識別的值可以用特殊的訪問器訪問。在任一種情況下,如果消息被序列化,則無法識別的值仍將與消息一起序列化。
有關如何在應用程序中使用消息枚舉的詳細信息,請參閱為您選擇的語言生成的代碼指南。
保留值
如果通過完全刪除枚舉條目或注釋來更新枚舉類型,將來的用戶可以在對該類型進行自己的更新時重用數值。如果他們以后加載舊版本的相同 .proto內容,這可能會導致嚴重的問題。包括數據損壞、隱私漏洞等。確保不會發生這種情況的一種方法是指定保留已刪除條目的數值(and/or名稱,這也會導致JSON序列化問題)。如果將來有任何用戶試圖使用這些標識符,協議緩沖區編譯器會報錯。您可以使用max關鍵字指定保留的數值范圍達到可能的最大值。
enum Foo { reserved 2, 15, 9 to 11, 40 to max; reserved "FOO", "BAR"; }
請注意,不能在同一保留語句中混合字段名和數值。