如何 cast/convert 一个结构到 Protobuf?
How to cast/convert a Struct to Protobuf?
我正在做一个个人项目并且是第一次使用 Go。我正在使用结构对数据进行操作并将数据存储在文件中,我正在使用 proto 作为编码器。
在项目中,我的原型定义看起来像这样
message Data {
string key = 1;
string value = 2;
}
message Record {
int64 size = 1;
Data data = 2;
}
我的结构看起来像这样
type KVData struct {
Key string
Value string
}
目前,这就是我创建原型数据的方式
kvData := KVData{Key: "name", Value: "A"}
record := &pb.Record{
Size: 20,
Data: &pb.Data{Key: "name", Value: "A"},
}
我正在寻找的是一种方法:
record := &pb.Record{
Size: 20,
Data: &((pb.Data)kvData), // Won't work
}
// or like Python
record := &pb.Record{
Size: 20,
Data: &(pb.Data{**kvData}), // Won't work
}
我尝试使用谷歌搜索,但找不到任何解释如何执行此操作的解决方案。
注意,我不只是想解决这个具体案例,我还想知道在结构和原型之间操作的推荐 Go 方式是什么(只使用原型?)?
你能得到的最接近的是这样的:
pbData := pb.Data(kvData) // convert kvData struct to pb.Data struct
record := &pb.Record{
Size: 20,
Data: &pbData,
}
注意:您不能像这样组合这两个步骤:
record := &pb.Record{
Size: 20,
Data: &(pb.Data(kvData)), // BROKEN: can't get address of a return-value
}
您可以在这里进行更多实验:https://play.golang.org/p/2AhWi0Khe4l
编辑: pre go 1.8 如果结构类型不完全相同(相同的标签等),则无法转换它们。更新游乐场 link 以进行演示不匹配的标签将转换为 go 1.8
或更高版本。
你不能,至少在 Go 1.12.7 中不能。
Go 的 Protobuf 编译器为从消息生成的每个结构添加了 3 个额外字段:
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
因此,您的 struct
和生成的字段具有不同的字段,并且不完全相同,因此不 assignable。
如果两个结构仅在标签上不同,则可以 convert it:
type Person struct {
Name string
Address *struct {
Street string
City string
}
}
var data *struct {
Name string `json:"name"`
Address *struct {
Street string `json:"street"`
City string `json:"city"`
} `json:"address"`
}
var person = (*Person)(data) // ignoring tags, the underlying types are identical
您必须手动创建一个新的 struct
实例。
您可以使用第三方库 gogofaster 从您的 .proto 文件生成 go 代码。
gogofaster 是一个更快的生成工具,它不包括结构中的额外字段 (XXX_*),从而使转换更简单(因为结构现在将是相同的)。
您可以在这里了解更多信息:https://github.com/gogo/protobuf
Uber 的 Prototool 也支持 gogofaster。
希望对您有所帮助。
我正在做一个个人项目并且是第一次使用 Go。我正在使用结构对数据进行操作并将数据存储在文件中,我正在使用 proto 作为编码器。
在项目中,我的原型定义看起来像这样
message Data {
string key = 1;
string value = 2;
}
message Record {
int64 size = 1;
Data data = 2;
}
我的结构看起来像这样
type KVData struct {
Key string
Value string
}
目前,这就是我创建原型数据的方式
kvData := KVData{Key: "name", Value: "A"}
record := &pb.Record{
Size: 20,
Data: &pb.Data{Key: "name", Value: "A"},
}
我正在寻找的是一种方法:
record := &pb.Record{
Size: 20,
Data: &((pb.Data)kvData), // Won't work
}
// or like Python
record := &pb.Record{
Size: 20,
Data: &(pb.Data{**kvData}), // Won't work
}
我尝试使用谷歌搜索,但找不到任何解释如何执行此操作的解决方案。
注意,我不只是想解决这个具体案例,我还想知道在结构和原型之间操作的推荐 Go 方式是什么(只使用原型?)?
你能得到的最接近的是这样的:
pbData := pb.Data(kvData) // convert kvData struct to pb.Data struct
record := &pb.Record{
Size: 20,
Data: &pbData,
}
注意:您不能像这样组合这两个步骤:
record := &pb.Record{
Size: 20,
Data: &(pb.Data(kvData)), // BROKEN: can't get address of a return-value
}
您可以在这里进行更多实验:https://play.golang.org/p/2AhWi0Khe4l
编辑: pre go 1.8 如果结构类型不完全相同(相同的标签等),则无法转换它们。更新游乐场 link 以进行演示不匹配的标签将转换为 go 1.8
或更高版本。
你不能,至少在 Go 1.12.7 中不能。
Go 的 Protobuf 编译器为从消息生成的每个结构添加了 3 个额外字段:
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
因此,您的 struct
和生成的字段具有不同的字段,并且不完全相同,因此不 assignable。
如果两个结构仅在标签上不同,则可以 convert it:
type Person struct {
Name string
Address *struct {
Street string
City string
}
}
var data *struct {
Name string `json:"name"`
Address *struct {
Street string `json:"street"`
City string `json:"city"`
} `json:"address"`
}
var person = (*Person)(data) // ignoring tags, the underlying types are identical
您必须手动创建一个新的 struct
实例。
您可以使用第三方库 gogofaster 从您的 .proto 文件生成 go 代码。
gogofaster 是一个更快的生成工具,它不包括结构中的额外字段 (XXX_*),从而使转换更简单(因为结构现在将是相同的)。
您可以在这里了解更多信息:https://github.com/gogo/protobuf
Uber 的 Prototool 也支持 gogofaster。
希望对您有所帮助。