I have the following 3 protobuf messages.
message Item {
uint32 ID = 1;
string Name = 2;
...
}
message ItemIdsRequest{
string batchUUID = 1;
repeated uint32 itemIds = 2;
}
message ItemsResponse{
string batchUUID = 1;
repeated Item items = 2;
}
A function retrieves a list of item ID's to later fetch all its details. These ID's are stored in the mssage ItemIdsRequest
along with a batchUUID
for aggregating via event-sourcing.
Then a function retrieves all details as a []messages.Item
from the int slice in messages.ItemIdsRequest
. I copy the batchUUID
from the message ItemIdsRequest
over into the message.ItemsResponse
.
But when I try to copy the returned []messages.Item
into belows message I get the error cannot use items (type []messages.Item as type []*item)
// returns []messages.Item
itemsPB, _ := api.getItems("", items.ItemIds...)
itemsResponse := &messages.ItemsResponse{
BatchUUID: uuid.NewV4().String(),
Items: itemsPB,
}
I cannot change the function to the following, because the item is a pointer, not the slice of items which the function returns. And I cannot have the functions return 'message.ItemsResponse'.
TLDR: I have two seperate protobuf structs. I am trying to set the []messages.items
in the messages.ItemsResponse
items
property but I am not allowed to because the generated protobuf code makes the messages.ItemsResponse
items
property a pointer. When I edit the autogenerated code and remove the pointer... everything works as intended.
type ItemsResponse struct {
BatchUUID string `protobuf:"bytes,1,opt,name=batchUUID,proto3" json:"batchUUID,omitempty"`
Items []*Item `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
I am new to protobuf and no expert on pointers (wanting to be) so I could also use some help understanding why its autogenerated into a pointer.
Protobuf documents that for repeated message fields the generated Go code will use a slice of pointers. This allows optional values, because in Go structs cannot be nil
, but pointers can.
If you have a slice of structs and you want to assign that to a variable or field which is a slice of pointers, you have to "manually" produce that value.
Use a simple loop to do that:
// returns []messages.Item
itemsPB, _ := api.getItems("", items.ItemIds...)
itemPtrs := make([]*messages.Item, len(itemsPB))
for i := range itemsPB {
itemPtrs[i] = &itemsPB[i]
}
itemsResponse := &messages.ItemsResponse{
BatchUUID: uuid.NewV4().String(),
Items: itemPtrs,
}
Note that the slice of pointers we assemble above points to the elements of the original itemsPB
slice.
If you modify api.getItems()
to return a slice of pointers ([]*messages.Item
), you could assign that without having to create a slice of pointers.