Go语言 有没有约束(泛型)类型参数的方法?

wvmv3b1j  于 2023-01-22  发布在  Go
关注(0)|答案(1)|浏览(148)

我刚刚开始学习泛型,所以我尝试为我的自定义数据库泛化一个驱动程序,操作一些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。

nmpmafwu

nmpmafwu1#

你可以这样做:

func Encode[M interface { *E; proto.Message }, E Entity](v M) ([]byte, error) {
    return proto.Marshal(v)
}

如果你想要比上面更简洁的语法,你可以删除消息约束:

type Message[E Entity] interface {
    *E
    proto.Message
}

func Encode[M Message[E], E Entity](v M) ([]byte, error) {
    return proto.Marshal(v)
}

https://go.dev/play/p/AYmSKYCfZ1_l

相关问题