登录
首页 >  Golang >  Go问答

是否有一种方法可以对(通用)类型参数进行约束?

来源:stackoverflow

时间:2024-02-11 18:15:24 203浏览 收藏

Golang小白一枚,正在不断学习积累知识,现将学习到的知识记录一下,也是将我的所得分享给大家!而今天这篇文章《是否有一种方法可以对(通用)类型参数进行约束?》带大家来了解一下##content_title##,希望对大家的知识积累有所帮助,从而弥补自己的不足,助力实战开发!


问题内容

我刚刚开始学习泛型。因此,我尝试为在某些 protobuf 消息上操作的自定义数据库通用化驱动程序。

我想找到一种方法来进一步约束我的泛型类型,但作为指针,即确保(告诉编译器)约束 E 实现了另一种方法。

首先,我限制了数据库可以处理的实体。

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() 方法,我所有的实体类型都实现了该方法,但它不受约束,编译器无法推断。

我还尝试将实体定义为:

type Entity interface {
   *pb.MsgA | *pb.MsgB | *pb.MsgC
   proto.Message
}

但是,除了我需要执行一些额外的 protreflect 操作来实例化实体指针引用的 proto.Messages 之外,这感觉不太对。


正确答案


你可以这样做:

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

今天关于《是否有一种方法可以对(通用)类型参数进行约束?》的内容介绍就到此结束,如果有什么疑问或者建议,可以在golang学习网公众号下多多回复交流;文中若有不正之处,也希望回复留言以告知!

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>