我刚刚开始学习泛型,所以我尝试为我的自定义数据库泛化一个驱动程序,操作一些protobuf消息。
我想找到一种方法来进一步约束我的泛型类型,但作为一个指针,即确保(告诉编译器)约束E实现了另一个方法。
首先,我限制了db可以处理的实体。
type Entity interface {
pb.MsgA | pb.MsgB | pb.MsgC
}
然后,编写了一个描述数据库功能的通用接口,以便不同的服务可以使用它来处理各自的原型消息:
type DB[E Entity] interface {
Get(...) (E, error)
List(...) ([]E, error)
...
}
到目前为止一切顺利。但是,我还希望这些实体被(反)序列化,以便在与数据库通信时通过网络发送、克隆和合并。类似于以下内容:
func Encode[E Entity](v *E) ([]byte, error) {
return proto.Marshal(v)
}
但是,上面的代码给我以下错误:
cannot use val (variable of type *E) as type protoreflect.ProtoMessage in argument to proto.Marshal: *E does not implement protoreflect.ProtoMessage (type *E is pointer to type parameter, not type parameter)
问题是proto.Marshal
需要实体(*E)来实现proto.Message
接口,即ProtoReflect()
方法,我的所有Entity类型都实现了该方法,但它不受约束,编译器无法推断。
我还试图将实体定义为:
type Entity interface {
*pb.MsgA | *pb.MsgB | *pb.MsgC
proto.Message
}
然而,这感觉不太对,另外我还需要做一些额外的proreflect操作来示例化实体指针引用的proto.messages。
1条答案
按热度按时间nmpmafwu1#
你可以这样做:
如果你想要比上面更简洁的语法,你可以删除消息约束:
https://go.dev/play/p/AYmSKYCfZ1_l