#go #proto
#Вперед #прото
Вопрос:
Я пишу функцию, которая принимает произвольное протосообщение и что-то с ним делает
func protoToSomething(in proto.Message) ([]byte, error) {
jsonBytes, protoJsonError := protojson.Marshal(in)
if protoJsonError != nil {
return nil, protoJsonError
}
stuff here...
}
Однако, когда я вызываю его с помощью этого:
model := myprotolib.MyRequest{
UserId: "3214",
UserName: "JohnDoe",
SomeValue: true,
}
data, _ := protoToSomething(model)
Я получаю это «myprotolib.MyRequest не реализует protoreflect .ProtoMessage (метод ProtoReflect имеет приемник указателя) «
Это выглядит точным, потому что, когда я смотрю на автоматически созданный протокод, он определяется с помощью
func (x *MyRequest) ProtoReflect() protoreflect.Message {
(Где получатель принимает указатель.)
Но когда я смотрю на определение в protoreflect / proto.go, я вижу
type ProtoMessage interface{ ProtoReflect() Message }
Итак, я в замешательстве и новичок в Go (хотя я профессионально использовал Protos, Java и C ) — как мне написать функцию, которая принимает произвольное протосообщение и выполняет с ним некоторые действия, включая protojson.Маршалл?
Комментарии:
1. Используйте
protoToSomething(amp;model)
2. Спасибо @BurakSerdar, это сработало, но можете ли вы помочь мне понять, почему? модель не является ссылкой, а функция protoToSomething принимает реальный прототип. Сообщение, так почему же то, что у меня было, не должно работать?
Ответ №1:
model
не реализует этот интерфейс, поскольку model
объявил этот метод для получателя указателя.
Если метод объявлен с получателем указателя, только указатели этого типа реализуют этот интерфейс, а не типы значений. То есть:
type I interface {
f()
}
type S struct {
}
func (s S) f() {}
type T struct {
}
func (t *T) f() {}
func W(intf I) {}
func main() {
s:=S{}
W(s) // This works. S has method f()
W(amp;s) // This works. *S has method f()
t:=T{}
W(t) // This does not work. T does not have f()
w(amp;t) // This works. *T has f()
}
Это по существу предотвращает непреднамеренную передачу копии значения, где необходим указатель.
Комментарии:
1. Почему бы Go не просто автоматически отправить указатель получателю указателя, точно так же, как он автоматически разыменовывает указатель, когда функция получателя ожидает значение?
2. Если вы вызовете
t.f()
, тоf
получите адресt
, поэтому он автоматически отправляет получателю указателя. Этот случай отличается. Вы передаете структуру в качестве интерфейса. СинтаксисW(t)
означает, что вы передаете копиюt
, а не ее адрес.