日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

google protobuf_protobuf 指南

發布時間:2025/3/8 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 google protobuf_protobuf 指南 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  • 簡介
  • 安裝
  • 語言定義
    • 特殊指令
    • 定義服務
    • JSON 支持
    • 選項
    • 生成代碼
    • 基礎類型
    • 更新 message
  • Golang 下使用
  • 參考

簡介

Protocol Buffers 是 google 出品的一種數據交換格式, 縮寫為 protobuf.

主要介紹 proto3 版本和 Golang 下的使用.

安裝

protobuf 分為編譯器和運行時兩部分. 編譯器直接使用預編譯的二進制文件即可, 可以從 releases 上下載.

protobuf 運行時就是不同語言對應的庫, 以 Golang 為例:

go get github.com/golang/protobuf/protoc-gen-go

語言定義

protobuf 現在有兩個版本, proto2 和 proto3. 本著學新不學舊的原則, 這里只介紹 proto3.

既然是一種數據交換格式, 必然是要學習它的語法的, 就像學習 JSON 一樣, 你總得知道如何定義.

默認的文件是 .proto.

下面是一個簡單的例子, 來自于官方文檔.

syntax = "proto3";message SearchRequest {string query = 1;int32 page_number = 2;int32 result_per_page = 3; }

首行定義了語法版本, 即使用 proto3 版本. 然后定義了一個名為 SearchRequest 的 message, 以及它包含的字段(鍵值對). message 的結構非常類似于各種語言中的 struct, dict 或者 map.

每個字段包括三個部分, 類型, 字段名和字段編號. 前兩個部分非常易懂, 主要解釋一下字段編號. 在同一個 message 中字段編號應該是唯一的, 用于在 message 的二進制格式(message binary format)中標識字段. 因此數字的大小決定了編碼的長度, 1-15 的數字只占用一個字節.

注釋語法是 // 和 /* ... */.

特殊指令

使用 reserved 注明已被廢棄的字段編號和字段名稱.

message Foo {reserved 2, 15, 9 to 11;reserved "foo", "bar"; }

使用 repeated 可以指定重復字段, 即數組.

message Test4 {repeated int32 d = 4 [packed=true]; }

使用 enum 定義枚舉類型. 每個枚舉定義都必須包含一個映射值為 0 的常量作為第一個元素.

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; }

定義枚舉時, 可以使用 allow_alias 選項允許枚舉值的別名.

enum EnumAllowingAlias {option allow_alias = true;UNKNOWN = 0;STARTED = 1;RUNNING = 1; // RUNNING 是 STARTED 的別名 }

類型也可以嵌套使用.

message SearchResponse {repeated Result results = 1; }message Result {string url = 1;string title = 2;repeated string snippets = 3; }

使用 import 可以導入外部定義.

import "myproject/other_protos.proto";

使用 import public 可以傳遞導入依賴, 通常用于被導入的 proto 文件需要更改的情況下.

import public "new.proto";

protocol 編譯器搜索的位置是命令行參數中的 -I/--proto_path flag. 如果沒有提供, 則搜索編譯器被調用時所在的目錄.

Any 類型可以讓你可以在沒有它們的 proto 定義時, 將 messages 用作內嵌的類型. 一個 Any 包括任意的二進制序列化的 message, 就像 bytes 類型那樣, 以及用作該類型的全局唯一的標識符 URL.

import "google/protobuf/any.proto";message ErrorStatus {string message = 1;repeated google.protobuf.Any details = 2; }

默認的類型 URL 是 type.googleapis.com/packagename.messagename.

如果你有一個 message 包括許多字段, 但同時最多只有一個字段會被設置, 可以使用 Oneof 特性來節省內存. Oneof 字段和普通的字段沒有區別, 除了所有這些 Oneof 字段共享內存, 且同時只能由一個字段被設置. 你可以使用特殊的 case() 或 WhichOneof() 方法檢查哪個字段被設置了, 具體方法名稱取決于實現的語言.

message SampleMessage {oneof test_oneof {string name = 4;SubMessage sub_message = 9;} }

可以在 Oneof 中添加任何類型的字段, 但不能使用 repeated.

使用 map 可以創建關聯映射.

map<key_type, value_type> map_field = N; map<string, Project> projects = 3;

key_type 可以是 integral 或 string 類型, 即 scalar 類型中除了 floating point types 和 bytes 以外的類型. value_type 可以是除 map 以外的任何類型.

使用 package 可以設置命名空間, 防止 message 類型沖突.

package foo.bar; message Open { ... }

在另一個 proto 文件中使用.

message Foo {...foo.bar.Open open = 1;... }

package 說明符會影響不同語言生成代碼的方式:

  • Python: 忽略 package 指令
  • Golang: package 用作 Go 包名, 除了你使用 option go_package 顯式聲明包名

定義服務

如果你想要和 RPC 系統集成使用, 你可以定義 RPC 服務接口, 編譯器會根據選擇的語言, 生成對應的服務接口代碼和存根.

service SearchService {rpc Search (SearchRequest) returns (SearchResponse); }

最常見的是和 gRPC 一起使用.

JSON 支持

proto3 支持 JSON 中的規范編碼, 具體的類型轉換關系, 查看官方文檔.

選項

有很多選項可以調節特性的行為, 完整的選項列表定義在 google/protobuf/descriptor.proto.

生成代碼

要生成代碼, 需要使用下面的命令, 對于 Golang 需要安裝額外的插件.

protoc --proto_path=IMPORT_PATH --cpp_out=DST_DIR --java_out=DST_DIR --python_out=DST_DIR --go_out=DST_DIR --ruby_out=DST_DIR --objc_out=DST_DIR --csharp_out=DST_DIR path/to/file.proto

基礎類型

標量值類型和各種語言間的轉換可以參考 官方文檔.

包括以下類型:

double float int32 int64 unit32 unit64 sint32 編碼負數比 int32 更高效 sint64 fixed32 固定四字節. 如果數字通常大于 2^28, 比 uint32 更高效 fixed64 sfixed32 負數優化版本的 fixed32 sfixed64 bool string bytes

更新 message

官方指南翻譯

  • 不要更改任何現有字段的字段編號.
  • 如果添加新的字段, 仍然可以使用新生成的代碼解析舊的 message 格式. 但應該自行處理新加字段的默認值. 使用新代碼創建的 message 也可以被舊代碼解析, 那些新字段會被忽略.
  • 字段可以被刪除, 只要不要復用那些字段編號. 要重命名字段, 可以給舊字段添加 OBSOLETE_ 前綴, 或者將字段編號設置為 reserved.
  • int32, uint32, int64, uint64, bool 是相互兼容的類型.
  • sint32 和 sint64 是相互兼容的, 但不兼容其他 int 類型.
  • string 和 bytes 可以是兼容的, 只要 bytes 是有效的 UTF-8.
  • 嵌入的 message 可以和 bytes 兼容, 如果 bytes 包含 message 的編碼后的版本.
  • fixed32 和 sfixed32 兼容, fixed64 和 sfixed64 兼容.
  • enum 在 wire 格式上兼容 int32, uint32, int64, uint64(如果值不合適會被截斷). 當 message 被反序列化時, 客戶端代碼可以用不同的方式對待它們. 比如, 未識別的 proto3 的 enum 類型將會保存在 message 中, 但它如何 表示是語言特定的. int 字段總是會保留它的值.
  • 將一個單個值更改為新 oneof 的成員是安全的且二進制兼容的. 移動多個字段到一個新的 oneof 可能是安全的, 如果你確保沒有 code 被多次設置. 移動任何字段到一個已存在的 oneof 是不安全的.

Golang 下使用

定義 protobuf 文件 hello.proto 的內容為:

syntax = "proto3";import "google/protobuf/any.proto";package hello; option go_package = "hello";message HelloReq {string name = 1; }message HelloResp {int32 code = 1;string greet = 2;google.protobuf.Any details = 3; }service HelloService {rpc Greet(HelloReq) returns (HelloResp); }

初始化項目, 并生成文件:

go mod init tzh.com/app go get github.com/golang/protobuf/protoc-gen-go mkdir hello # 假設 protoc3 已經解壓好了 .protoc3binprotoc.exe --proto_path=. --go_out=./hello hello.proto

main.go 如下:

package mainimport ("crypto/rand""fmt""github.com/golang/protobuf/proto""github.com/golang/protobuf/ptypes/any"hello "tzh.com/app/hello" )func main() {req := &hello.HelloReq{Name: "hello",}details := make([]byte, 10)rand.Read(details)resp := &hello.HelloResp{Code: 1,Greet: "hello name",Details: &any.Any{Value: details},}fmt.Println(req.String())fmt.Println(resp.String())// 序列化data, _ := proto.Marshal(req)fmt.Println(data)// 反序列化newReq := &hello.HelloReq{}proto.Unmarshal(data, newReq)fmt.Println(newReq)fmt.Println("text format", proto.MarshalTextString(req))}

如果你去看生成的代碼, 會發現沒有 HelloService 相關的內容, 這是因為沒有使用 gRPC.

參考

  • github
  • go protobuf
  • proto3
  • Go Generated Code
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的google protobuf_protobuf 指南的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。