Объявления Go Protobuf и необязательные поля в Go Struct (строковые указатели)

Я столкнулся с небольшой проблемой с Protoc и моей существующей структурой, которая содержит пустые строковые поля.

Структура, которую я пытаюсь сериализовать для передачи, содержит несколько полей, которые можно обнулять в json (поэтому мы можем различать null, "" и заданное значение).

type Message struct {
  Path *string `json:"path"`
}

Так что, если пользователь отправляет пустую строку JSON {} Путь будет nil и нет "", в то время как {"path":""} также действителен и отличается от случая {"path": null},

proto3 Декларация, которую я придумала, очевидно, выглядит следующим образом required а также optional выпал из proto3:

syntax = "proto3";
message Message {
  string Path = 1;
}

После запуска Protoc я получаю структуру, которая выглядит следующим образом, и все значения string и нет способа объявить их *string:

type Message struct {
  Path string `protobuf:"bytes,1,opt,name=Path,proto3" json:"Path,omitempty"`
}

Очевидно, я не могу назначить этот массив из моей существующей структуры. Но даже если бы я написал утомительный код отображения с target.Path = *source.Path с соответствующими проверками нулевого указателя и т. д. Я бы потерял тройное значение моей исходной структуры (nil, "", "value").

Любые предложения о том, как действовать здесь или есть расширение Go Protobuf для этого? Или как можно описать эту прото-декларацию?

3 ответа

Решение

Proto3 возвращает нулевое значение, даже если поле не установлено. В настоящее время нет способа различить, было ли установлено поле или нет.

Смотрите Github выпуск № 15.

Возможные решения:

  • Используйте proto2 вместо proto3.
  • Используйте гульнарое расширение.
  • Использовать google.protobuf.FieldMask расширение см. в разделе "Общие шаблоны проектирования" в Руководстве по разработке API Google: частичные ответы и поля вывода.

Вероятно, не решение:

Напишите утомительный код сопоставления с target.Path = *source.Path с соответствующим нулевым указателем.

... так как это не будет работать для типов int, где нулевое значение равно 0.

/questions/24024922/kak-opredelit-neobyazatelnoe-pole-v-protobuf-3/55260904#55260904 поддержка proto3 опционально с флагом --experimental_allow_proto3_optional

В моем случае я решил эту проблему несколькими пакетами:

  1. https://github.com/gogo/protobuf
  2. https://github.com/golang/protobuf

Мой прото-файл выглядит так:

syntax = "proto3";

import "google/protobuf/wrappers.proto";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";

message Message {
  google.protobuf.StringValue path = 1 [(gogoproto.wktpointer) = true];
}

Команда для генерации кода go, которую я использовал, выглядит так:

protoc -I. -I%GOPATH%/src --gogofaster_out=plugins=grpc:. proto/*.proto

Сгенерированный файл go выглядит так:

type Message struct {
    Path *string `protobuf:"bytes,1,opt,name=path,json=path,proto3,wktptr" json:"path,omitempty"`
}
Другие вопросы по тегам