Go泛型函数中proto.Unmarshal报错及new(T)结合Protobuf用法咨询
问题解答
代码重现
import "google.golang.org/protobuf/proto" type Msg[T any] interface { *T proto.Message } func Handle[T any, U Msg[T]](cb func(req U) (proto.Message, error)) { msg := new(T) if err := proto.Unmarshal([]byte{}, msg); err != nil { // 错误处理 } _, _ = cb(msg) } func main() { Handle(doSomething) // 原代码笔误:donSomething → doSomething } func doSomething(req *pb.Hello) (proto.Message, error) { _ = proto.Unmarshal([]byte{}, req) return nil, nil }
问题1:为何Handle泛型函数中,无法将*T类型的msg传入proto.Unmarshal?
proto.Unmarshal的第二个参数要求是实现proto.Message的指针类型。虽然你定义了Msg[T]接口约束U是*T且实现proto.Message,但Handle中T的约束仅为any,编译器无法推导*T一定实现proto.Message——U的约束只作用于自身,不会反向约束T的指针类型。因此msg(类型为*T)无法满足proto.Unmarshal的参数要求。
同时cb(msg)也会报错:回调函数要求参数为U类型,而msg是*T,编译器无法确认二者等价。
问题2:如何在泛型函数中结合Protobuf正确使用new(T)?
提供两种可行调整方案:
方案一:直接约束*T实现proto.Message
修改Handle的泛型约束,明确要求*T必须实现proto.Message,这样new(T)得到的实例可直接传入proto.Unmarshal:
func Handle[T any](cb func(req *T) (proto.Message, error)) where *T: proto.Message { msg := new(T) if err := proto.Unmarshal([]byte{}, msg); err != nil { // 处理错误 } _, _ = cb(msg) } // 调用方式不变 func main() { Handle(doSomething) }
方案二:利用Msg[T]接口显式转换类型
既然U是*T且实现proto.Message,可以将new(T)显式转换为U类型,同时满足proto.Message约束和回调参数类型:
func Handle[T any, U Msg[T]](cb func(req U) (proto.Message, error)) { // 将*T转换为U类型,编译器可确认其实现proto.Message msg := U(new(T)) if err := proto.Unmarshal([]byte{}, msg); err != nil { // 处理错误 } _, _ = cb(msg) }
该方案保留了你原有的Msg[T]接口设计,同时解决了类型不匹配问题。
内容的提问来源于stack exchange,提问作者capsiamese
相关产品推荐
相关产品推荐

