国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁(yè) > news >正文

外國(guó)優(yōu)秀網(wǎng)站設(shè)計(jì)青島關(guān)鍵詞優(yōu)化平臺(tái)

外國(guó)優(yōu)秀網(wǎng)站設(shè)計(jì),青島關(guān)鍵詞優(yōu)化平臺(tái),哪些網(wǎng)站做寫(xiě)字樓出租,山西百度網(wǎng)站建設(shè)Protobuf 3 入門(mén) 1. 什么是序列化? 1.1 概念 序列化(Serialization 或 Marshalling) 是指將數(shù)據(jù)結(jié)構(gòu)或?qū)ο蟮臓顟B(tài)轉(zhuǎn)換成可存儲(chǔ)或傳輸?shù)母袷?。反向操作稱(chēng)為反序列化(Deserialization 或 Unmarshalling),它…

Protobuf 3 入門(mén)

1. 什么是序列化?

1.1 概念

序列化(Serialization 或 Marshalling) 是指將數(shù)據(jù)結(jié)構(gòu)或?qū)ο蟮臓顟B(tài)轉(zhuǎn)換成可存儲(chǔ)或傳輸?shù)母袷?/strong>。反向操作稱(chēng)為反序列化(Deserialization 或 Unmarshalling),它的作用是將序列化的數(shù)據(jù)恢復(fù)成原始的數(shù)據(jù)結(jié)構(gòu)或?qū)ο蟆?/p>

簡(jiǎn)單來(lái)說(shuō),序列化就像“打包”,反序列化就像“解包”。

2.1 為什么需要序列化?

在計(jì)算機(jī)系統(tǒng)中,數(shù)據(jù)通常是以內(nèi)存中的對(duì)象(如 struct、class)形式存在的,而內(nèi)存數(shù)據(jù)不能直接在不同程序之間傳輸,必須先轉(zhuǎn)換成可存儲(chǔ)或可傳輸?shù)母袷?。序列化的主要用途包?#xff1a;

  1. 數(shù)據(jù)存儲(chǔ):將數(shù)據(jù)保存到文件、數(shù)據(jù)庫(kù)等,例如:
    • 日志文件
    • 配置文件(如 JSON、YAML)
    • 持久化存儲(chǔ)(如 Redis、MongoDB)
  2. 數(shù)據(jù)傳輸:在不同進(jìn)程或網(wǎng)絡(luò)之間傳輸數(shù)據(jù),例如:
    • 前端和后端通信(Web API)
    • 微服務(wù)之間的通信
    • 遠(yuǎn)程調(diào)用(RPC,如 gRPC)
  3. 數(shù)據(jù)緩存:比如將復(fù)雜的對(duì)象序列化后存入 Redis,提高訪問(wèn)速度。
  4. 跨語(yǔ)言兼容:不同編程語(yǔ)言的數(shù)據(jù)結(jié)構(gòu)不一樣,序列化后可以在不同語(yǔ)言之間傳輸數(shù)據(jù)。

3.1 序列化的方式

不同的序列化格式適用于不同的應(yīng)用場(chǎng)景,常見(jiàn)的格式包括:

格式特點(diǎn)可讀性序列化速度數(shù)據(jù)大小適用場(chǎng)景
JSON文本格式,廣泛使用可讀適中較大Web API,前端后端通信
XML結(jié)構(gòu)化文本,標(biāo)簽冗余可讀早期 Web API,配置文件
YAML結(jié)構(gòu)更簡(jiǎn)潔,適合人閱讀可讀適中較大配置文件(Kubernetes、Docker)
ProtobufGoogle 開(kāi)發(fā)的高效二進(jìn)制格式不可讀微服務(wù)、gRPC、高性能應(yīng)用
MessagePack類(lèi)似 JSON,但體積更小不可讀移動(dòng)端、嵌入式系統(tǒng)
ThriftFacebook 開(kāi)發(fā)的高效序列化格式不可讀分布式系統(tǒng),RPC
Avro適用于大數(shù)據(jù)(如 Hadoop)不可讀適中大數(shù)據(jù)處理
BSONMongoDB 的序列化格式不可讀適中適中MongoDB 數(shù)據(jù)存儲(chǔ)

2. 什么是 Protobuf?

2.1 概念

Protobuf(Protocol Buffers)是 Google 開(kāi)發(fā)的一種高效、跨平臺(tái)、可擴(kuò)展數(shù)據(jù)序列化協(xié)議。它可以將數(shù)據(jù)轉(zhuǎn)換為緊湊的二進(jìn)制格式,用于不同系統(tǒng)之間進(jìn)行高效的數(shù)據(jù)傳輸和存儲(chǔ)。

簡(jiǎn)單理解:

  • 它類(lèi)似于 JSON,但比 JSON 體積更小、速度更快。
  • 它類(lèi)似于 XML,但格式更緊湊、解析更高效。
  • 它適用于微服務(wù)、RPC(遠(yuǎn)程調(diào)用)、數(shù)據(jù)存儲(chǔ)等高性能場(chǎng)景。

2.2 為什么使用 Protobuf?

特點(diǎn)ProtobufJSONXML
格式二進(jìn)制文本文本
體積最小較大最大
解析速度最快一般最慢
可讀性不可讀可讀可讀
跨語(yǔ)言支持
支持 RPC是(gRPC)

如果你的項(xiàng)目涉及:

  • 高性能數(shù)據(jù)通信(微服務(wù)、RPC、物聯(lián)網(wǎng)、游戲服務(wù)器)
  • 跨語(yǔ)言數(shù)據(jù)傳輸(Go、Java、Python、C++、Rust 等)
  • 大規(guī)模數(shù)據(jù)存儲(chǔ)(日志、數(shù)據(jù)庫(kù)、緩存)

那么 Protobuf 是比 JSON、XML 更好的選擇

2.3 Protobuf 的使用場(chǎng)景

  1. 微服務(wù)通信(gRPC)
    • 適用于 Go、Java、Python、C++ 等語(yǔ)言的微服務(wù)之間高效通信。
    • 結(jié)合 gRPC 使用,可以比傳統(tǒng) REST API 更快。
  2. 數(shù)據(jù)存儲(chǔ)
    • 存儲(chǔ)日志、緩存數(shù)據(jù)(如存入 Redis)時(shí),Protobuf 體積小,能節(jié)省存儲(chǔ)空間。
  3. 跨語(yǔ)言數(shù)據(jù)交換
    • 由于 Protobuf 支持多種編程語(yǔ)言,可以在不同語(yǔ)言的系統(tǒng)之間進(jìn)行高效數(shù)據(jù)傳輸。
  4. 移動(dòng)端和 IoT(物聯(lián)網(wǎng))
    • 移動(dòng)端和 IoT 設(shè)備通常帶寬和存儲(chǔ)受限,Protobuf 適用于傳輸小體積數(shù)據(jù),提高性能。

3. 簡(jiǎn)單解釋 Protobuf 例子

3.1 Protobuf 文件 simple.proto

syntax = "proto3"; // 使用 proto3 語(yǔ)法message SearchRequest {  // 定義一個(gè)數(shù)據(jù)結(jié)構(gòu)(類(lèi)似 JSON 對(duì)象)string query = 1;      // 搜索關(guān)鍵詞(字符串)int32 page_number = 2; // 頁(yè)碼(整數(shù))int32 result_per_page = 3; // 每頁(yè)返回的結(jié)果數(shù)(整數(shù))
}

解釋

  • syntax = "proto3"; 指定使用 proto3 語(yǔ)法。
  • message SearchRequest 定義了一個(gè)數(shù)據(jù)結(jié)構(gòu)(類(lèi)似 JSON 對(duì)象)。
  • 每個(gè)字段的格式:
    • 類(lèi)型string、int32
    • 字段名稱(chēng)querypage_number、result_per_page
    • 字段編號(hào)12、3,用于唯一標(biāo)識(shí)字段,不能重復(fù))

3.2 編譯 Protobuf 代碼

Protobuf 需要編譯后才能用于編程語(yǔ)言(Go、Java、Python 等)。 在終端運(yùn)行:

protoc --go_out=. simple.proto
  • protoc 是 Protobuf 編譯器
  • --go_out=. 表示生成 Go 代碼,并存放在當(dāng)前目錄
  • simple.proto 是需要編譯的 Protobuf 文件

不同語(yǔ)言對(duì)應(yīng)的參數(shù):

語(yǔ)言編譯參數(shù)
C++--cpp_out=.
Java--java_out=.
Python--python_out=.
C#--csharp_out=.
Rust--rust_out=.

最終會(huì)生成 simple.pb.go,這個(gè)文件包含 Go 代碼,用于操作 SearchRequest 結(jié)構(gòu)。

3.3 生成的 Go 代碼

編譯后會(huì)生成如下 Go 結(jié)構(gòu):

type SearchRequest struct {Query         string `protobuf:"bytes,1,opt,name=query,proto3" json:"query,omitempty"`PageNumber    int32  `protobuf:"varint,2,opt,name=page_number,json=pageNumber,proto3" json:"page_number,omitempty"`ResultPerPage int32  `protobuf:"varint,3,opt,name=result_per_page,json=resultPerPage,proto3" json:"result_per_page,omitempty"`
}

解釋

  • SearchRequeststruct,對(duì)應(yīng) .proto 文件中的 message SearchRequest。
  • Query、PageNumberResultPerPage 變量對(duì)應(yīng) .proto 里的字段。
  • protobuf:"..." 里的信息用于 Protobuf 序列化和解析。

3.4 如何使用這個(gè) Go 結(jié)構(gòu)

package mainimport ("fmt""google.golang.org/protobuf/proto"
)func main() {// 創(chuàng)建 SearchRequest 實(shí)例request := &SearchRequest{Query:         "golang protobuf",PageNumber:    1,ResultPerPage: 10,}// **序列化**data, _ := proto.Marshal(request)// **反序列化**newRequest := &SearchRequest{}proto.Unmarshal(data, newRequest)fmt.Println(newRequest) // 輸出: {Query:golang protobuf PageNumber:1 ResultPerPage:10}
}

解釋

  1. 創(chuàng)建 SearchRequest 結(jié)構(gòu),并填充數(shù)據(jù)。
  2. 使用 proto.Marshal(request) 序列化,轉(zhuǎn)換成二進(jìn)制格式(適合網(wǎng)絡(luò)傳輸)。
  3. 使用 proto.Unmarshal(data, newRequest) 反序列化,把二進(jìn)制恢復(fù)成 Go 結(jié)構(gòu)。

4. Protobuf 的數(shù)據(jù)類(lèi)型

4.1 標(biāo)量數(shù)據(jù)類(lèi)型(Scalar Types)

Protobuf 提供了一些常見(jiàn)的基本數(shù)據(jù)類(lèi)型,對(duì)應(yīng)不同語(yǔ)言的變量類(lèi)型。

4.1.1 數(shù)值類(lèi)型
Protobuf 類(lèi)型說(shuō)明適用場(chǎng)景
int3232 位整數(shù)(默認(rèn)編碼)適用于較小的整數(shù)
int6464 位整數(shù)(默認(rèn)編碼)適用于較大的整數(shù)
uint32無(wú)符號(hào) 32 位整數(shù)適用于只能為正數(shù)的情況
uint64無(wú)符號(hào) 64 位整數(shù)適用于大數(shù)且不允許負(fù)數(shù)
sint3232 位有符號(hào)整數(shù)(ZigZag 編碼)適用于可能包含負(fù)數(shù)的整數(shù)
sint6464 位有符號(hào)整數(shù)(ZigZag 編碼)適用于包含負(fù)數(shù)的長(zhǎng)整數(shù)
fixed3232 位整數(shù)(固定長(zhǎng)度編碼)適用于數(shù)值分布較均勻的場(chǎng)景
fixed6464 位整數(shù)(固定長(zhǎng)度編碼)適用于較大的定長(zhǎng)整數(shù)
sfixed3232 位有符號(hào)整數(shù)(固定長(zhǎng)度編碼)適用于負(fù)數(shù)較多的場(chǎng)景
sfixed6464 位有符號(hào)整數(shù)(固定長(zhǎng)度編碼)適用于較大的負(fù)數(shù)

區(qū)別:

  • int32/int64:默認(rèn)使用 Varint 編碼(數(shù)據(jù)小的時(shí)候占用字節(jié)更少)。
  • sint32/sint64:使用 ZigZag 編碼,負(fù)數(shù)編碼更高效。
  • fixed32/fixed64:使用固定長(zhǎng)度存儲(chǔ),適合數(shù)值分布均勻的情況。
  • sfixed32/sfixed64:固定長(zhǎng)度的有符號(hào)整數(shù)。
4.1.2 浮點(diǎn)數(shù)類(lèi)型
Protobuf 類(lèi)型說(shuō)明適用場(chǎng)景
float32 位浮點(diǎn)數(shù)適用于存儲(chǔ)小數(shù)
double64 位浮點(diǎn)數(shù)適用于更高精度的小數(shù)

注意:

  • float4 個(gè)字節(jié),精度有限。
  • double8 個(gè)字節(jié),適用于更高精度計(jì)算。
4.1.3 布爾類(lèi)型
Protobuf 類(lèi)型說(shuō)明適用場(chǎng)景
bool布爾值 (true/false)適用于開(kāi)關(guān)、狀態(tài)等

示例:

message Example {bool is_active = 1; // true or false
}
4.1.4 字符串和字節(jié)類(lèi)型
Protobuf 類(lèi)型說(shuō)明適用場(chǎng)景
stringUTF-8 編碼的字符串存儲(chǔ)文本信息
bytes原始字節(jié)數(shù)據(jù)適用于存儲(chǔ)二進(jìn)制數(shù)據(jù)(如文件、圖片等)

示例:

message Example {string name = 1;bytes file_data = 2;
}

注意:

  • string 只能存儲(chǔ) 文本(UTF-8 編碼)。
  • bytes 可以存儲(chǔ) 任意二進(jìn)制數(shù)據(jù)(如圖片、視頻等)。

4.2 復(fù)雜數(shù)據(jù)類(lèi)型

4.2.1 數(shù)組(Repeated)

使用 repeated 關(guān)鍵字表示 列表/數(shù)組

message Example {repeated string hobbies = 1;repeated int32 scores = 2;
}
  • repeated string hobbies = 1; → 表示字符串?dāng)?shù)組
  • repeated int32 scores = 2; → 表示整數(shù)數(shù)組

注意

  • 在 Protobuf 3 中,repeated 類(lèi)型默認(rèn)是可選的,不需要額外的 optional 關(guān)鍵字。
4.2.2 鍵值對(duì)(Map)

Protobuf 3 提供 map<K, V> 類(lèi)型來(lái)存儲(chǔ)鍵值對(duì)

message Example {map<string, int32> scores = 1; // key: string, value: int32
}
  • map<string, int32> 表示 鍵為字符串,值為整數(shù) 的字典。
  • 生成代碼后,會(huì)轉(zhuǎn)換成 Go 語(yǔ)言的 map[string]int32。
4.2.3 枚舉類(lèi)型(Enum)
enum Status {UNKNOWN = 0;  // 枚舉必須從 0 開(kāi)始ACTIVE = 1;INACTIVE = 2;
}message User {Status status = 1;
}
  • enum 只能用于定義固定的值(類(lèi)似 int)。
  • 第一個(gè)枚舉值必須是 0,防止解析錯(cuò)誤。
4.2.4 嵌套 Message
message Address {string city = 1;string street = 2;
}message Person {string name = 1;Address address = 2; // 直接嵌套 Address
}
  • Person 結(jié)構(gòu)里包含 Address 結(jié)構(gòu),可以用于復(fù)雜數(shù)據(jù)存儲(chǔ)。

4.3 Protobuf 類(lèi)型與不同語(yǔ)言的對(duì)應(yīng)關(guān)系

Protobuf 類(lèi)型GoJavaPythonC++
int32int32intintint32_t
int64int64longintint64_t
floatfloat32floatfloatfloat
doublefloat64doublefloatdouble
boolboolbooleanboolbool
stringstringStringstrstd::string
bytes[]bytebyte[]bytesstd::string
map<K,V>map[K]VMap<K,V>dictstd::map<K,V>
repeated[]TList<T>liststd::vector<T>

4.4 Protobuf 3 語(yǔ)法示例

syntax = "proto3";message Person {string name = 1;int32 age = 2;bool is_active = 3;repeated string hobbies = 4;map<string, int32> scores = 5;
}

這個(gè) Person 結(jié)構(gòu)包含:

  • string name → 姓名
  • int32 age → 年齡
  • bool is_active → 是否激活
  • repeated string hobbies → 興趣愛(ài)好(數(shù)組)
  • map<string, int32> scores → 課程成績(jī)(鍵值對(duì))

5. Protobuf 其他字段

5.1 Oneof(互斥字段)

5.1.1 什么是 oneof

oneof 關(guān)鍵字用于定義一組互斥字段,即同一時(shí)間只能有一個(gè)字段被設(shè)置。它的作用類(lèi)似于 C 語(yǔ)言的 union,但比 union 更智能,可以判斷當(dāng)前設(shè)置的是哪個(gè)字段。

5.1.2 為什么要用 oneof

proto3 版本中,所有字段都有默認(rèn)值,比如:

message Example {int64 id = 1;
}
  • 如果 id 沒(méi)有被設(shè)置,默認(rèn)值是 0
  • 但如果 id 被顯式設(shè)置為 0,你就無(wú)法判斷這個(gè) 0 是默認(rèn)值,還是用戶(hù)真的設(shè)置了 0。

oneof 解決了這個(gè)問(wèn)題,因?yàn)樗峁┝艘粋€(gè)字段狀態(tài)檢查功能,讓你可以判斷哪個(gè)字段被設(shè)置了。

5.1.3 oneof 語(yǔ)法
message Response {oneof result {string success_message = 1; // 成功時(shí)的消息int32 error_code = 2; // 失敗時(shí)的錯(cuò)誤碼}
}
  • oneof 內(nèi)的字段是互斥的,最多只能設(shè)置一個(gè)。
  • 如果 success_message 被設(shè)置,error_code 就不能被設(shè)置,反之亦然。
  • 如果不設(shè)置任何字段,oneof 字段為空。

適用場(chǎng)景

  • API 響應(yīng)(成功返回 success_message,失敗返回 error_code)。
  • 狀態(tài)表示(例如訂單可能是“待支付”或“已完成”,但不能同時(shí)處于這兩個(gè)狀態(tài))。
5.1.4 oneof 在 Go 語(yǔ)言中的使用

Protobuf 生成的 Go 代碼會(huì)使用 isXxx() 方法 來(lái)判斷哪個(gè)字段被賦值。

示例:Go 代碼

package mainimport ("fmt""google.golang.org/protobuf/proto"
)// 假設(shè) Protobuf 生成的 Go 結(jié)構(gòu)如下:
type Response struct {// 這是 oneof 生成的字段Result isResponse_Result `protobuf_oneof:"result"`
}type isResponse_Result interface {isResponse_Result()
}type Response_SuccessMessage struct {SuccessMessage string
}type Response_ErrorCode struct {ErrorCode int32
}// 實(shí)現(xiàn) isResponse_Result 接口
func (*Response_SuccessMessage) isResponse_Result() {}
func (*Response_ErrorCode) isResponse_Result() {}func main() {// **成功時(shí)返回 success_message**resp1 := &Response{Result: &Response_SuccessMessage{SuccessMessage: "Operation successful"}}// **失敗時(shí)返回 error_code**resp2 := &Response{Result: &Response_ErrorCode{ErrorCode: 404}}// 判斷是哪個(gè)字段被設(shè)置switch v := resp1.Result.(type) {case *Response_SuccessMessage:fmt.Println("Success:", v.SuccessMessage)case *Response_ErrorCode:fmt.Println("Error:", v.ErrorCode)}switch v := resp2.Result.(type) {case *Response_SuccessMessage:fmt.Println("Success:", v.SuccessMessage)case *Response_ErrorCode:fmt.Println("Error:", v.ErrorCode)}
}

輸出

Success: Operation successful
Error: 404
  • oneof 生成了 isResponse_Result 接口,允許我們判斷哪個(gè)字段被設(shè)置。
  • switch v := resp.Result.(type) 語(yǔ)法用于檢查當(dāng)前 oneof 字段的類(lèi)型。
5.1.5 oneof 的應(yīng)用場(chǎng)景
  • REST API / gRPC 響應(yīng)(成功返回?cái)?shù)據(jù),失敗返回錯(cuò)誤碼)
  • 訂單狀態(tài)未支付 / 已支付
  • 用戶(hù)身份驗(yàn)證郵箱登錄 / 手機(jī)號(hào)登錄
  • 存儲(chǔ)不同類(lèi)型的數(shù)據(jù)文本 / 圖片 / 視頻

5.2 Reserved(保留字段)

5.2.1 什么是reserved

在 Protobuf 3 中,reserved 關(guān)鍵字用于保留字段編號(hào)或名稱(chēng),防止將來(lái)代碼演進(jìn)時(shí)誤用已刪除的字段。
這可以避免 API 變更時(shí)的兼容性問(wèn)題,確保舊數(shù)據(jù)不會(huì)被錯(cuò)誤解析。

5.2.2 為什么需要 reserved

當(dāng)你刪除或修改字段時(shí),如果不使用 reserved,那么:

  1. 未來(lái)新添加的字段可能意外復(fù)用舊的字段編號(hào),導(dǎo)致數(shù)據(jù)解析出錯(cuò)。
  2. 舊數(shù)據(jù)仍然可能使用被刪除的字段,導(dǎo)致意外行為。
5.2.3 reserved 語(yǔ)法

你可以用 reserved 關(guān)鍵字保留字段編號(hào)或名稱(chēng),防止后續(xù)被重新使用。

保留字段編號(hào)

message User {reserved 2, 4 to 6; // 不能再使用編號(hào) 2、4、5、6
}
  • 以后不能再使用 2、4、5、6 作為字段編號(hào)。
  • 如果后續(xù)嘗試用 field = 2;,編譯時(shí)會(huì)報(bào)錯(cuò)。

保留字段名稱(chēng)

message User {reserved "old_name", "deprecated_field"; // 不能再使用這些字段名
}
  • 以后不能再使用 “old_name” 和 “deprecated_field” 作為字段名。

同時(shí)保留編號(hào)和名稱(chēng)

message User {reserved 2, 4 to 6;reserved "old_name", "deprecated_field";
}
  • 這樣可以同時(shí)保留編號(hào)和字段名稱(chēng),防止意外復(fù)用。
5.2.4 reserved 作用
  • 避免舊數(shù)據(jù)解析錯(cuò)誤:如果編號(hào)被誤用,舊數(shù)據(jù)可能被錯(cuò)誤解析。
  • 防止 API 兼容性問(wèn)題:如果 API 變更,保留字段可以確保舊客戶(hù)端不會(huì)收到無(wú)效數(shù)據(jù)。
  • 讓代碼更可維護(hù):明確告訴后續(xù)開(kāi)發(fā)者哪些字段不能使用。

5.3 Any(存儲(chǔ)任意數(shù)據(jù))

5.3.1 什么是 Any

Any 是 Protobuf 3 提供的一種特殊類(lèi)型,允許存儲(chǔ)任意類(lèi)型的 Protobuf 消息,適用于動(dòng)態(tài)數(shù)據(jù)場(chǎng)景。
它可以在不修改 .proto 結(jié)構(gòu)的情況下,支持不同類(lèi)型的數(shù)據(jù),類(lèi)似于 JSON 里的 objectmap<string, any>。

5.3.2 Any 的作用
  • 存儲(chǔ)動(dòng)態(tài)數(shù)據(jù):如果一個(gè)字段的類(lèi)型可能變化(例如可能是 UserOrder),可以使用 Any 而不需要改 .proto 文件。
  • 實(shí)現(xiàn)靈活的 API 設(shè)計(jì):適用于插件系統(tǒng)、事件系統(tǒng)、日志系統(tǒng),讓不同的子系統(tǒng)傳遞不同的數(shù)據(jù)結(jié)構(gòu)。
  • 避免頻繁修改 Protobuf 定義:當(dāng)不同的客戶(hù)端需要傳輸不同的數(shù)據(jù)類(lèi)型時(shí),使用 Any 可以減少 API 變更的影響。
5.3.3 Any 的基本用法

(1)導(dǎo)入 Any 類(lèi)型

Any 需要導(dǎo)入 google/protobuf/any.proto

import "google/protobuf/any.proto"; // 引入 Any 類(lèi)型message Response {string message = 1; google.protobuf.Any data = 2; // 存儲(chǔ)任意類(lèi)型
}
  • message 是普通字段,存儲(chǔ)文本信息。
  • dataAny 類(lèi)型,可以存儲(chǔ)任何 Protobuf 消息。

(2)嵌套不同的消息

假設(shè)你有兩種不同的消息 UserOrder

message User {string name = 1;int32 age = 2;
}message Order {int32 order_id = 1;double price = 2;
}message Response {string message = 1;google.protobuf.Any data = 2; // 可以存儲(chǔ) User 或 Order
}
  • data 字段可以存儲(chǔ) UserOrder,而不需要修改 Response 結(jié)構(gòu)。
  • 這樣,Response 可以在不同場(chǎng)景下使用,不受數(shù)據(jù)類(lèi)型影響
5.3.4 Any 在 Go 語(yǔ)言中的使用

(1)安裝 Protobuf 依賴(lài)

在 Go 代碼中,需要 protoanypb(處理 Any 類(lèi)型):

go get google.golang.org/protobuf/proto
go get google.golang.org/protobuf/types/known/anypb

(2)Go 代碼示例

package mainimport ("fmt""google.golang.org/protobuf/proto""google.golang.org/protobuf/types/known/anypb"
)// 定義 User 和 Order 結(jié)構(gòu)
type User struct {Name stringAge  int32
}type Order struct {OrderId int32Price   float64
}// Response 結(jié)構(gòu),包含 Any 字段
type Response struct {Message stringData    *anypb.Any
}func main() {// 創(chuàng)建 User 結(jié)構(gòu)user := &User{Name: "Alice", Age: 25}// 將 User 結(jié)構(gòu)封裝到 Any 里anyData, _ := anypb.New(user)// 創(chuàng)建 Response 并存儲(chǔ) User 數(shù)據(jù)resp := &Response{Message: "User data",Data:    anyData,}// **序列化**data, _ := proto.Marshal(resp)// **反序列化**newResp := &Response{}proto.Unmarshal(data, newResp)// **解析 Any 字段**newUser := &User{}newResp.Data.UnmarshalTo(newUser)fmt.Println("Message:", newResp.Message)fmt.Println("User Name:", newUser.Name, "Age:", newUser.Age)
}

(3)Go 代碼解釋

  1. 封裝數(shù)據(jù):
    • 使用 anypb.New(user)User 結(jié)構(gòu)轉(zhuǎn)換成 Any 類(lèi)型。
  2. 序列化 Response
    • 使用 proto.Marshal(resp) 進(jìn)行序列化,便于存儲(chǔ)或傳輸。
  3. 反序列化 Response
    • 使用 proto.Unmarshal(data, newResp) 解析 Response 結(jié)構(gòu)。
  4. 解析 Any 數(shù)據(jù):
    • newResp.Data.UnmarshalTo(newUser) 解析 Any 字段,恢復(fù) User 結(jié)構(gòu)。

6. Protobuf 編碼原理

Protobuf 使用高效的二進(jìn)制格式來(lái)存儲(chǔ)和傳輸數(shù)據(jù),其中最關(guān)鍵的編碼方式之一是 Varint(變長(zhǎng)整數(shù)編碼)。它的核心思想是:

  • 數(shù)值越小,占用字節(jié)越少
  • 數(shù)值越大,占用字節(jié)越多
  • 高效存儲(chǔ),減少帶寬消耗

6.1 什么是 Varint?

Varint(變長(zhǎng)整數(shù)編碼) 是一種特殊的編碼方式,它可以使用 1 到 N 個(gè)字節(jié) 表示整數(shù)。

  • 小數(shù)占用更少字節(jié)(如 1 只需要 1 個(gè)字節(jié))。
  • 大數(shù)會(huì)自動(dòng)擴(kuò)展到多個(gè)字節(jié)(如 300 需要 2 個(gè)字節(jié))。

6.2 Varint 編碼規(guī)則

  1. 每個(gè)字節(jié)的最高位(MSB,Most Significant Bit)是“是否還有后續(xù)字節(jié)的標(biāo)志”
    • 最高位為 0:表示這是最后一個(gè)字節(jié)。
    • 最高位為 1:表示后面還有字節(jié)。
  2. 剩下的 7 位存儲(chǔ)數(shù)據(jù)(低位優(yōu)先,LSB)。

6.3 具體示例

(1)數(shù)字 1 的 Varint 編碼

0000 0001  (只有 1 個(gè)字節(jié))
  • 最高位 0:表示這是最后一個(gè)字節(jié)。
  • 其余 7 位 000 0001(= 1)。

存儲(chǔ)方式:

[0000 0001]  → 1 字節(jié)

(2)數(shù)字 300 的 Varint 編碼

先看二進(jìn)制表示:

300 = 100101100(9 位)

需要拆成 7 位 + 剩余部分

低 7 位: 0101100  → 0x2C(44)
高 2 位: 0000010  → 0x02(2)
  • 第一字節(jié):1010 1100(0xAC)
    • 最高位 1(表示后面還有字節(jié))。
    • 剩余 7 位存 010 1100(= 44)。
  • 第二字節(jié):0000 0010(0x02)
    • 最高位 0(表示這是最后一個(gè)字節(jié))。
    • 剩余 7 位存 000 0010(= 2)。

最終編碼

[1010 1100]  [0000 0010]  → 2 字節(jié)(0xAC 0x02)

6.4 Wire Type(數(shù)據(jù)類(lèi)型編碼)

Protobuf 數(shù)據(jù)存儲(chǔ)為 鍵值對(duì)(key-value) 形式,每個(gè)字段的 key 也需要編碼。
字段的 key字段編號(hào) + Wire Type 組成。

Wire Type作用
Varint0變長(zhǎng)整數(shù)(int32, int64, bool, enum
Fixed64164 位定長(zhǎng)(double, fixed64, sfixed64
Length-delimited2變長(zhǎng)數(shù)據(jù)(string, bytes, message, repeated
Start group3已廢棄(用于嵌套數(shù)據(jù))
End group4已廢棄
Fixed32532 位定長(zhǎng)(float, fixed32, sfixed32

存儲(chǔ)格式

[字段編號(hào) << 3] | [Wire Type]  [數(shù)據(jù)]

字段編號(hào)左移 3 位,低 3 位存 Wire Type。

6.5 例子:Protobuf 編碼解析

假設(shè) Person 結(jié)構(gòu)如下:

message Person {int32 id = 1;        // 1 字段編號(hào)string name = 2;     // 2 字段編號(hào)
}

數(shù)據(jù):

{"id": 150,"name": "Alice"
}

編碼過(guò)程

  1. 字段 id = 150

    • 字段編號(hào) = 1
    • Wire Type = 0(Varint)
    • key = (1 << 3) | 0 = 0000 1000 (0x08)
    • 150 的 Varint 編碼:1001 0110 0000 0001(0x96 0x01)

    最終存儲(chǔ)

    [0x08]  [0x96 0x01]  (字段編號(hào) 1,Varint)
    
  2. 字段 name = "Alice"

    • 字段編號(hào) = 2
    • Wire Type = 2(Length-delimited,字符串)
    • key = (2 << 3) | 2 = 0001 0001 (0x12)
    • "Alice" = 5 個(gè)字節(jié)(0x41 0x6C 0x69 0x63 0x65

    最終存儲(chǔ)

    [0x12]  [0x05]  [0x41 0x6C 0x69 0x63 0x65]
    

6.6 解析 Protobuf 二進(jìn)制數(shù)據(jù)

假設(shè)收到如下二進(jìn)制數(shù)據(jù):

08 96 01 12 05 41 6C 69 63 65

逐字節(jié)解析:

  1. 08 = 0000 1000(字段編號(hào) 1,Wire Type 0,Varint)
  2. 96 01 = 150(Varint 解碼)
  3. 12 = 0001 0010(字段編號(hào) 2,Wire Type 2,字符串)
  4. 05 = 長(zhǎng)度 5
  5. 41 6C 69 63 65 = "Alice"

最終解析為:

{"id": 150,"name": "Alice"
}
http://m.aloenet.com.cn/news/28949.html

相關(guān)文章:

  • 網(wǎng)站建設(shè)做什么百度收錄查詢(xún)工具
  • 互聯(lián)網(wǎng) 政府門(mén)戶(hù)網(wǎng)站建設(shè)方案最新國(guó)際新聞50條簡(jiǎn)短
  • 網(wǎng)站后期維護(hù)費(fèi)用邯鄲seo營(yíng)銷(xiāo)
  • 做黃色網(wǎng)站怎么賺錢(qián)精準(zhǔn)防控高效處置
  • 價(jià)格劃算的東莞建網(wǎng)站公司優(yōu)化營(yíng)商環(huán)境評(píng)價(jià)
  • 東莞物流公司張家界seo
  • 江蘇 做網(wǎng)站推廣目標(biāo)怎么寫(xiě)
  • 國(guó)外電商網(wǎng)站如何做icp備案網(wǎng)頁(yè)seo是什么意思
  • 泵 品牌網(wǎng)站建設(shè)深圳網(wǎng)站建設(shè)系統(tǒng)
  • 情人節(jié)給女朋友做網(wǎng)站線上推廣軟件
  • 南京公司網(wǎng)站開(kāi)發(fā)合肥瑤海區(qū)
  • 一個(gè)jsp做的購(gòu)物小網(wǎng)站搜索引擎優(yōu)化的方法和技巧
  • wordpress文庫(kù)插件搜索引擎優(yōu)化的流程
  • wordpress裝在根目錄文件夾中_如何通過(guò)域名直接訪問(wèn)?google關(guān)鍵詞seo
  • 四川省建筑設(shè)計(jì)院排名seo哪家公司好
  • 動(dòng)態(tài)網(wǎng)站數(shù)據(jù)庫(kù)設(shè)計(jì)seo搜索引擎優(yōu)化排名哪家更專(zhuān)業(yè)
  • 在網(wǎng)上如何找做網(wǎng)站的人品牌營(yíng)銷(xiāo)策略分析
  • 企業(yè)網(wǎng)站建設(shè)費(fèi)用定金怎么做賬關(guān)鍵詞查網(wǎng)址
  • 昆山做網(wǎng)站哪家好百度競(jìng)價(jià)排名廣告定價(jià)鮮花
  • 做網(wǎng)站用什么軟件知乎google瀏覽器下載
  • 企業(yè)做定制網(wǎng)站的好處自助建站免費(fèi)建站平臺(tái)
  • 網(wǎng)站出現(xiàn)的的問(wèn)題軟文營(yíng)銷(xiāo)案例
  • 泰安網(wǎng)站制作seo海外
  • 做電池的外貿(mào)網(wǎng)站廣州日新增51萬(wàn)人
  • 哪個(gè)網(wǎng)站不花錢(qián)可以做招聘互聯(lián)網(wǎng)營(yíng)銷(xiāo)的特點(diǎn)
  • wordpress下載器插件廣東seo價(jià)格是多少錢(qián)
  • 網(wǎng)站建設(shè) 日志免費(fèi)外鏈網(wǎng)
  • 做網(wǎng)站可以在哪兒接活app推廣拉新接單平臺(tái)
  • 梅州專(zhuān)業(yè)網(wǎng)站建設(shè)教程高端品牌網(wǎng)站建設(shè)
  • flash網(wǎng)站的優(yōu)勢(shì)廈門(mén)谷歌seo公司