解组 GRPC 对通用类型的响应问题

Issue with Unmarshalling GRPC Response To Generic Type

我正在尝试使用泛型将 JSON 对象转换为具有枚举的 GRPC 响应,即:

type GRPCResponse {
    str string
    enu EnumType
}

type EnumType int32
const (
    Type1 EnumType = 0
    Type2 EnumType = 1
)

解组函数如下所示:

func assertHTTPResponseOK[T any](t *testing.T, endpoint string) T {
    body, err := GetResponse(endpoint)

    var v T
    err := json.Unmarshal(body, &v)
    require.Nil(t, err)
    return v
}

调用它的代码如下所示:

assertHTTPResponseOK[*GRPCResponse](t, "some-endpoint")

有问题的 JSON 对象如下所示:

{"str":"hello", "enu": "Type2"}

我收到如下错误:

json: cannot unmarshal string into Go struct field GRPCResponse.enu of type EnumType

从类似的问题中,我看到通常的建议是使用 jsonpb.Unmarshalprotojson.Unmarshal 而不是典型的 json.Unmarshal.

在更改 Unmarshal 函数时,我还必须将 T 更改为 protoreflect.ProtoMessage。但是,这使我无法将指向v的指针传递给Unmarshal,因为它是指向接口的指针,而不是接口。当然我也不能传入nil指针(不取v的地址)

所以我的问题是:

  1. 有没有办法让这个泛型对象的指针满足接口protoreflect.ProtoMessage
  2. 是否有更好的 Unmarshalling 函数更适合我的问题?

我最终传入了我正在解组的对象。

obj := new(GRPCResponse)
assertHTTPResponseOK[*GRPCResponse](t, ctx, "some-endpoint", obj)
func assertHTTPResponseOK[T protoreflect.ProtoMessage](t *testing.T, ctx context.Context, endpoint string, object T) {
    body, err := GetResponse(endpoint)
    require.Nil(t, err)

    err = protojson.Unmarshal(body, object)
    require.Nil(t, err)
}

这是一个 generics-friendly 原型解组器,它避免传递第二个类型,代价是反射调用以查看指针内部的类型并调用它的构造函数。

        var msg T // Constrained to proto.Message

        // Peek the type inside T (as T= *SomeProtoMsgType)
        msgType := reflect.TypeOf(msg).Elem()

        // Make a new one, and throw it back into T
        msg = reflect.New(msgType).Interface().(T)

        errUnmarshal := proto.Unmarshal(body, msg)