I am working on a personal project & using Go for the first time. I am using structs for operating on the data and for storing the data in a file, I am using proto as the encoder.
In the project, my proto definition looks something like this
message Data {
string key = 1;
string value = 2;
}
message Record {
int64 size = 1;
Data data = 2;
}
and my struct looks like this
type KVData struct {
Key string
Value string
}
Currently, this is how I am creating proto data
kvData := KVData{Key: "name", Value: "A"}
record := &pb.Record{
Size: 20,
Data: &pb.Data{Key: "name", Value: "A"},
}
What I am looking for is a way to do this:
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
}
I tried googling but couldn't find any solution explaining how to do this.
Note, I am not just trying to solve this specific case, I also want to know what's the recommended Go way to operate between structs and proto(use only proto?)?
You cannot, at least not in Go 1.12.7.
Go's Protobuf compiler adds 3 extra fields to each struct generated from a message:
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
Therefore your struct
and generated one have different fields and are not identical as per, therefore not assignable.
If two structs differ only in the tags, it is possible to 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
You have to create a new struct
instance manually.
The closest you can get is something like:
pbData := pb.Data(kvData) // convert kvData struct to pb.Data struct
record := &pb.Record{
Size: 20,
Data: &pbData,
}
Note: you cannot combine these two steps like so:
record := &pb.Record{
Size: 20,
Data: &(pb.Data(kvData)), // BROKEN: can't get address of a return-value
}
You can experiment more here: https://play.golang.org/p/2AhWi0Khe4l
EDIT: pre go 1.8 struct types could not be converted if they were not exactly identical (same tags etc.) Updated playground link to demo mismatched tags will convert with go 1.8
or later.