Как принять произвольное протосообщение в качестве входных данных и вызвать protojson.Маршалируйте с ним

#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 , а не ее адрес.