Объявления 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
В моем случае я решил эту проблему несколькими пакетами:
Мой прото-файл выглядит так:
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"`
}