Go Protobuf declarations and optional Fields in Go Struct (string pointers)

不打扰是莪最后的温柔 提交于 2021-01-27 14:09:17

问题


I am running into a bit of a problem with Protoc and my existing struct that contains nullable string fields.

The struct I am trying to serialize for transmission contains a bunch of fields that are nullable in json (so we can distinguish between null, "" and a set value).

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

So if a user sends a empty json string {} the Path will be nil and not "", whereas {"path":""} is also valid and a different case from {"path": null}.

The proto3 declaration I came up with obviously looks like this (and is optional as required and optional got dropped from proto3:

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

After running Protoc I end up with a struct that looks like this and all values are string and no way to declare them as *string:

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

Obviously I can't assign to this array from my existing struct. But even if I were to write the tedious mapping code with target.Path = *source.Path with the appropriate null pointer checks etc I'd loose the triple meaning of my source struct (nil, "", "value").

Any suggestions on how to proceed here or if there is an extension to the Go Protobuf to do this? Or how would one go about describing this proto declaration?


回答1:


Proto3 returns the Zero Value even if a field isn't set. Currently there is no way to distinguish if a field has been set or not.

See Github issue #15.

Possible solutions:

  • Use proto2 instead of proto3.
  • Use gogoproto's nullable extension.
  • Use the google.protobuf.FieldMask extension, see Common Design Patterns from the Google API Design Guide: Partial Responses and Output Fields.

Probably not a solution:

Write the tedious mapping code with target.Path = *source.Path with the appropriate null pointer.

... as this won't work for int types where the zero value is 0.




回答2:


In my case, I solved this problem with several packages:

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

My proto file looks like this:

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];
}

The command for generating the go code, which I used look like this:

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

The generated go file looks like this:

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


来源:https://stackoverflow.com/questions/57039033/go-protobuf-declarations-and-optional-fields-in-go-struct-string-pointers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!