卓越飞翔博客卓越飞翔博客

卓越飞翔 - 您值得收藏的技术分享站
技术文章34805本站已运行393

有没有办法约束(通用)类型参数?

有没有办法约束(通用)类型参数?

php小编柚子探讨了一个常见问题:有没有办法约束(通用)类型参数?在PHP中,我们经常需要对函数或方法的参数进行类型约束,以确保传入的参数满足特定的类型要求。然而,对于通用类型参数,如数组或对象,目前还没有直接的约束方式。但是,我们可以通过编写更加严格的类型检查逻辑来实现对通用类型参数的约束,以确保参数的正确性和一致性。在本文中,我们将探讨几种实现通用类型参数约束的方法,以及它们的优缺点。

问题内容

我刚刚开始学习泛型。因此,我尝试为在某些 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://www.php.cn/link/20ba66f905957b34253d9d7abde919f3

卓越飞翔博客
上一篇: KV Store 中的密钥是如何锁定的?
下一篇: 返回列表
留言与评论(共有 0 条评论)
   
验证码:
隐藏边栏