解组 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.Unmarshal
或 protojson.Unmarshal
而不是典型的 json.Unmarshal
.
在更改 Unmarshal 函数时,我还必须将 T 更改为 protoreflect.ProtoMessage
。但是,这使我无法将指向v
的指针传递给Unmarshal
,因为它是指向接口的指针,而不是接口。当然我也不能传入nil指针(不取v的地址)
所以我的问题是:
- 有没有办法让这个泛型对象的指针满足接口
protoreflect.ProtoMessage
?
- 是否有更好的 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)
我正在尝试使用泛型将 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.Unmarshal
或 protojson.Unmarshal
而不是典型的 json.Unmarshal
.
在更改 Unmarshal 函数时,我还必须将 T 更改为 protoreflect.ProtoMessage
。但是,这使我无法将指向v
的指针传递给Unmarshal
,因为它是指向接口的指针,而不是接口。当然我也不能传入nil指针(不取v的地址)
所以我的问题是:
- 有没有办法让这个泛型对象的指针满足接口
protoreflect.ProtoMessage
? - 是否有更好的 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)