protobuf ditakrifkan seperti berikut:
syntax = "proto3" message hugemessage { // omitted } message request { string name = 1; hugemessage payload = 2; }
Dalam satu kes, saya menerima hugemessage
,我想用其他字段打包它,然后将该消息传输给其他人。因此,我必须将 hugemessage
二进制文件unmarshal放入go结构中,将其打包到request
中,然后再次marshal。由于 hugemessage
的 hgue 大小,unmarshal 和 marshal 的成本难以承受。那么我可以重用 hugemessage
binari daripada seseorang tanpa mengubah definisi protobuf?
func main() { // receive it from file or network, not important. bins, _ := os.ReadFile("hugeMessage.dump") var message HugeMessage _ = proto.Unmarshal(bins, &message) // slow request := Request{ name: "xxxx", payload: message, } requestBinary, _ := proto.Marshal(&request) // slow // send it. os.WriteFile("request.dump", requestBinary, 0644) }
Jawapan ringkasnya ialah: Tidak, tiada cara mudah atau standard untuk mencapai ini.
Strategi yang paling jelas ialah melakukannya seperti yang anda lakukan sekarang - unmarshal hugemessage
,将其设置为 request
dan kemudian marshal lagi. Permukaan API protobuf Golang tidak benar-benar menyediakan cara untuk melakukan lebih banyak - dan untuk alasan yang baik.
Maksudnya, terdapat cara untuk mencapai apa yang anda mahu lakukan. Tetapi ini tidak semestinya selamat atau boleh dipercayai, jadi anda perlu menimbang kos itu dengan apa yang anda miliki sekarang.
Satu cara untuk mengelakkan pembongkaran adalah dengan memanfaatkan cara mesej biasanya bersiri
message request { string name = 1; hugemessage payload = 2; }
..bersamaan dengan
message request { string name = 1; bytes payload = 2; }
.. mana payload
包含针对某些 hugemessage
调用 marshal(...)
hasilnya.
Jadi, jika kita mempunyai definisi berikut:
syntax = "proto3"; message hugemessage { bytes field1 = 1; string field2 = 2; int64 field3 = 3; } message request { string name = 1; hugemessage payload = 2; } message rawrequest { string name = 1; bytes payload = 2; }
Kod berikut:
req1, err := proto.Marshal(&pb.Request{ Name: "name", Payload: &pb.HugeMessage{ Field1: []byte{1, 2, 3}, Field2: "test", Field3: 948414, }, }) if err != nil { panic(err) } huge, err := proto.Marshal(&pb.HugeMessage{ Field1: []byte{1, 2, 3}, Field2: "test", Field3: 948414, }) if err != nil { panic(err) } req2, err := proto.Marshal(&pb.RawRequest{ Name: "name", Payload: huge, }) if err != nil { panic(err) } fmt.Printf("equal? %t\n", bytes.Equal(req1, req2))
Output equal? true
Tidak jelas sama ada "kebiasaan" ini boleh dipercayai sepenuhnya, dan tiada jaminan ia akan terus berfungsi selama-lamanya. Jelas sekali rawrequest
类型必须完全镜像 request
jenis, ini tidak sesuai.
Pilihan lain ialah membina mesej dengan cara yang lebih manual, iaitu menggunakan pakej protowire - sekali lagi, jangan ragu, berhati-hati disyorkan.
Atas ialah kandungan terperinci Bolehkah saya menggunakan semula perduaan protobuf sedia ada semasa menyusun mesej yang mengandunginya? (protobuf3). Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!