如何将结构转换/转换为Protobuf?

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.