为了账号安全,请及时绑定邮箱和手机立即绑定

使用泛型实现可比较的结构

使用泛型实现可比较的结构

Go
胡说叔叔 2022-11-08 15:13:30
考虑以下版本 go1.18beta2 linux/amd64 的代码片段    type Vector[T comparable] struct {       data_ []T    }        func (v *Vector[T]) Contains(e T) bool {       for _, x := range v.data_ {          if x == e {             return true          }       }       return false    }        func TestVector(t *testing.T) {       v2 := Vector[Vector[int]]{}    }这不会编译并给出错误:“Vector[int] does not implement comparable”仅仅是因为Vector没有定义相等运算符。但是,我找不到如何定义它们。问题:这种创建可比较结构的方法是否不允许,为什么?还是文档还没有写好?
查看完整描述

1 回答

?
一只斗牛犬

TA贡献1784条经验 获得超2个赞

约束comparable由语言规范预先声明和支持。您不能“手动”使类型实现它。该文档在规范中可用(在Type Constraints下):


预先声明的接口类型可比较表示所有可比较的具体(非接口)类型的集合。具体来说,类型 T 在以下情况下实现可比较:


T不是接口类型,T支持操作 == 和 !=; 或者

T是一个接口类型,并且类型T集中的每个类型都实现了可比性。

您的类型Vector[T comparable]不满足任何这些条件。它不是接口类型,也不支持相等操作,因为它的一个字段data_ []T由于是切片而无法比较——即使元素类型受comparable.


约束的目的comparable实际上只是允许使用==和!=运算符编写通用代码。如果一个类型在设计上是不可比较的,那么你就不能编写这样的代码。即使Vector没有类型参数也是如此。


如果您的目标是实例化Vector[Vector[T]]并允许在 的实例之间进行相等性测试Vector[T],您可能需要添加一个Equal处理此特定用例的方法——只允许使用与接收器相同的类型参数实例化的向量:


func (v *Vector[T]) Equal(e Vector[T]) bool {

    // test equality in a way that makes sense for this type

}

值得一提的是,有一种方法可以自行Vector[T comparable]比较,data_即将字段更改为指向切片的指针:


type Vector[T comparable] struct {

    data_ *[]T

}

Vector[Vector[int]]现在用编译实例化。然而,除了用结构字面量(操场)进行初始化非常麻烦之外,它还带有指针比较的所有警告。进一步来说:


如果两个指针值指向同一个变量,或者两者的值都为零,则它们的值相等。指向不同的零大小变量的指针可能相等,也可能不相等。


现在比较测试和字段中x == e存储的内存地址是否相同。这可能会扭曲比较两个实例的语义——如果两个向量实例持有对同一切片的引用,那么说它们相等是否正确?也许。这取决于您的程序想要做出的假设。就个人而言,我认为这实际上并不比使用单独的方法和/或重新设计数据类型更好,但像往常一样,YMMV。data_xeVector[T]Equal


另请注意,如果您实例化为Vector[float64]并比较NaN值,则比较将是错误的。


查看完整回答
反对 回复 2022-11-08
  • 1 回答
  • 0 关注
  • 130 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号