考虑版本 go1.18beta2 linux/amd64 的以下代码片段
\n type Vector[T comparable] struct {\n data_ []T\n }\n \n func (v *Vector[T]) Contains(e T) bool {\n for _, x := range v.data_ {\n if x == e {\n return true\n }\n }\n return false\n }\n \n func TestVector(t *testing.T) {\n v2 := Vector[Vector[int]]{}\n }\nRun Code Online (Sandbox Code Playgroud)\n这不会编译并给出错误:\xe2\x80\x9cVector[int] does not implement comparable\xe2\x80\x9d只是因为Vector没有定义相等运算符。但是,我找不到如何定义它们。
问题:这种创建可比较结构的方法是否不允许,为什么?或者文档还没有写好?
\n该约束comparable是由语言规范预先声明和支持的。您不能“手动”让类型实现它。该文档可在规范中找到(在Type Constraints下):
\n\n预先声明的接口类型可比较表示所有可比较的具体(非接口)类型的集合。具体来说,类型 T 实现可比较的条件是:
\n\n
\n- \n
T不是接口类型,T支持 == 和 != 操作;或者- \n
T是一个接口类型,并且T\的类型集中的每个类型都实现了可比较的。
您的类型Vector[T comparable]不满足任何这些条件。它不是一种接口类型,并且不支持相等操作,因为data_ []T即使元素类型受 约束,它的一个字段由于是切片 \xe2\x80\x94 而不具有可比性comparable。
约束的目的comparable实际上只是允许使用==and!=运算符编写通用代码。如果类型在设计上不可比较,则无法编写此类代码。Vector即使没有类型参数也是如此。
如果您的目标是实例化Vector[Vector[T]]并允许 的实例之间进行相等性测试Vector[T],您可能需要添加一个Equal方法来处理此特定用例 \xe2\x80\x94 仅允许使用与接收器相同类型参数实例化的向量:
func (v *Vector[T]) Equal(e Vector[T]) bool {\n // test equality in a way that makes sense for this type\n}\nRun Code Online (Sandbox Code Playgroud)\n值得一提的是,有一种方法可以使其Vector[T comparable]自身进行比较,即将该data_字段更改为指向切片的指针:
type Vector[T comparable] struct {\n data_ *[]T\n}\nRun Code Online (Sandbox Code Playgroud)\n现在通过Vector[Vector[int]]编译进行实例化。然而,除了用结构体文字( playground )初始化非常麻烦之外,它还带有指针比较的所有注意事项。进一步来说:
\n\n如果两个指针值指向同一个变量或者两者的值为 nil,则它们相等。指向不同零大小变量的指针可能相等也可能不相等。
\n
现在比较测试 和字段x == e中存储的内存地址是否相同。这可能会扭曲比较两个实例 \xe2\x80\x94 的语义,如果两个向量实例持有对同一切片的引用,那么说两个向量实例相等是否正确?或许。这取决于您的程序想要做出的假设。就我个人而言,我认为这实际上并不比使用单独的方法和/或重新设计数据类型更好,但像往常一样,YMMV。data_xeVector[T]Equal
另请注意,如果实例化为Vector[float64]并比较NaN值,则比较结果将为 false。