如何在 Golang 中将 proto 数组编组(使用 protojson 包)为 json?

Suk*_*esh 9 json go protocol-buffers protobuf-go

如何在Golang中使用protojson包实现以下功能?

协议缓冲区:

type ProtoResp struct {
  state         protoimpl.MessageState
  sizeCache     protoimpl.SizeCache
  unknownFields protoimpl.UnknownFields

  Xesp isActionResponse_Xesp `protobuf_oneof:"xesp"`
  TimeTakena string `protobuf:"bytes,9,opt,name=time_takena,json=timeTakena,proto3" json:"time_takena,omitempty"`
}
Run Code Online (Sandbox Code Playgroud)

因此,我需要将 proto 数组编组为 json。例如,

type ProtoResp struct {
  state         protoimpl.MessageState
  sizeCache     protoimpl.SizeCache
  unknownFields protoimpl.UnknownFields

  Xesp isActionResponse_Xesp `protobuf_oneof:"xesp"`
  TimeTakena string `protobuf:"bytes,9,opt,name=time_takena,json=timeTakena,proto3" json:"time_takena,omitempty"`
}
Run Code Online (Sandbox Code Playgroud)

我该如何整理这个protoResps

目前,protojson.Marshal函数可以封送ProtoResp,但不能封送[]ProtoResp作为其原型片段。

我还需要稍后将其解组回[]ProtoResp

提前致谢。

Zek*_* Lu 2

我想这json.Marshal(protoResps)对你不起作用,因为该文件protojson规定:

该包产生的输出与标准“encoding/json”包不同,后者无法在协议缓冲区消息上正确运行。

一种解决方法仍然是使用encoding/json,但用 pakcage 编组/解组每个项目protojson

选项 1:实施json.Marshalerjson.Unmarshaler

如果ProtoResp是本地类型,则修改它以实现MarshalerUnmarshaler接口:

import (
    "google.golang.org/protobuf/encoding/protojson"
)

func (r *ProtoResp) MarshalJSON() ([]byte, error) {
    return protojson.Marshal(r)
}

func (r *ProtoResp) UnmarshalJSON(data []byte) error {
    return protojson.Unmarshal(data, r)
}
Run Code Online (Sandbox Code Playgroud)

然后就可以安全地使用encoding/json包来编组/解组[]*ProtoResp(不应该复制 的实例ProtoResp,大多数时候,您想要保存一个指针。*ProtoResp从现在开始我将使用)。

选项2:用于json.RawMessage延迟编码/解码

如果ProtoResp不是本地类型,解决方法是使用json.RawMessage延迟编码/解码。这种方法会消耗更多的内存。

import (
    "encoding/json"

    "google.golang.org/protobuf/encoding/protojson"
)

func Marshal(protoResps []*ProtoResp) ([]byte, error) {
    raw := make([]json.RawMessage, len(protoResps))
    for i, p := range protoResps {
        r, err := protojson.Marshal(p)
        if err != nil {
            return nil, err
        }
        raw[i] = r
    }

    return json.Marshal(raw)
}

func Unmarshal(data []byte) ([]*ProtoResp, error) {
    var raw []json.RawMessage
    if err := json.Unmarshal(data, &raw); err != nil {
        return nil, err
    }
    protoResps := make([]*ProtoResp, len(raw))
    for i, r := range raw {
        p := &ProtoResp{}
        if err := protojson.Unmarshal(r, p); err != nil {
            return nil, err
        }
        protoResps[i] = p
    }

    return protoResps, nil
}
Run Code Online (Sandbox Code Playgroud)