在Go泛型中,为什么我不能在可比较约束中使用顺序运算符?

huangapple go评论83阅读模式
英文:

In Go generics, why can't I use comparable constraint with order operators?

问题

我正在探索go泛型(1.18 beta),并且有关于比较两个数值的问题(一个简单的方法,接受两个值并返回较大的数)。为此,我正在创建一个自定义的数值类型,涵盖了以下类型集合(在函数getBiggerNumber中):

int | int8 | int16 | int32 | int64 | float32 | float64

然而,我添加了另一个函数,但这次不是使用自定义类型,而是使用了一个comparable内置约束(在函数getBiggerNumberWithComparable中)。

但是下面的代码在这个方法上报错,错误信息为:

"invalid operation: cannot compare t1 > t2 (operator > not defined on T)"?

有任何想法为什么在内置的可比较类型上>操作无法工作?

package main

import "fmt"

type numbers interface {
	int | int8 | int16 | int32 | int64 | float32 | float64
}

func getBiggerNumber[T numbers](t1, t2 T) T {
	if t1 > t2 {
		return t1
	}
	return t2
}

func getBiggerNumberWithComparable[T comparable](t1, t2 T) T {
	if t1 > t2 { // ./generics-sample.go:17:5: invalid operation: cannot compare t1 > t2 (operator > not defined on T)
		return t1
	}
	return t2
}

func main() {
	fmt.Println(getBiggerNumber(2.5, -4.0)) 
	fmt.Println(getBiggerNumberWithComparable(2.5, -4.0))
}
英文:

I am exploring go generics (1.18 beta), and have questions related to comparing two numerical values (a simple method that takes two values and returns a greater number).

For that, I am creating a custom numeric type that covers this type set (in the function getBiggerNumber):

int | int8 | int16 | int32 | int64 | float32 | float64

However, added one more function but this time instead of using a custom type had used a comparable built-in constraint (in the function getBiggerNumberWithComparable).

But below code gives an error on this method as

> "invalid operation: cannot compare t1 > t2 (operator > not defined on T)"?

Any idea why the > operation did not work on built-in comparable types?

package main

import "fmt"

type numbers interface {
	int | int8 | int16 | int32 | int64 | float32 | float64
}

func getBiggerNumber[T numbers](t1, t2 T) T {
	if t1 > t2 {
		return t1
	}
	return t2
}

func getBiggerNumberWithComparable[T comparable](t1, t2 T) T {
	if t1 > t2 { // ./generics-sample.go:17:5: invalid operation: cannot compare t1 > t2 (operator > not defined on T)
		return t1
	}
	return t2
}

func main() {
	fmt.Println(getBiggerNumber(2.5, -4.0)) 
	fmt.Println(getBiggerNumberWithComparable(2.5, -4.0))
}

答案1

得分: 33

comparable是对支持相等运算符==!=的类型的约束。语言规范在类型约束中定义了这一点。

值得注意的是,这包括可以用作映射键的任何内容,包括具有可比较字段的数组和结构体。(在运行时可能导致恐慌的比较,例如接口,在Go 1.20之前被排除在外)

确实,在Go语言规范中,比较运算符包括顺序运算符(<, >, <=, >=)。这种术语的选择可能让你感到困惑。然而,规范也对此进行了澄清:

> 相等运算符==!=适用于可比较的操作数。顺序运算符<, <=, >, 和 >=适用于有序的操作数。

Go 1.21

可以使用标准库中的cmp.Ordered

> 新的cmp包定义了类型约束Ordered和两个新的通用函数Less和Compare,它们对有序类型非常有用。

Go 1.18 到 1.20

在Go 1.18中,支持&gt;&lt;等顺序运算符的可用约束是constraints.Ordered<sup>1</sup>:

type Ordered interface {
	Integer | Float | ~string
}

<hr>

<sup>1:请注意,golang.org/x/exp包是实验性的。它的内容不能保证与新的Go版本向后兼容,但您可以随时将所需的定义复制粘贴到自己的代码中。</sup>

英文:

comparable is the constraint for types that support equality operators == and !=. The language spec defines this in Type constraints.

Notably, this includes anything that can be used as a map key, including arrays and structs with comparable fields. (Types where the comparison may panic at run time, e.g. interfaces, are excluded until Go 1.20).

It is true that in the Go language specifications, the comparison operators include order operators as (&lt;, &gt;, &lt;=, &gt;=). This choice of terminology probably is what confuses you. However the specs also disambiguate:

> The equality operators == and != apply to operands that are comparable. The ordering operators &lt;, &lt;=, &gt;, and &gt;= apply to operands that are ordered.

Go 1.21

Use cmp.Ordered from the standard library.

> The new cmp package defines the type constraint Ordered and two new generic functions Less and Compare that are useful with ordered types.

Go 1.18 to 1.20

In Go 1.18 the available constraint that supports the order operators such as &gt; and &lt; is constraints.Ordered<sup>1</sup>:

type Ordered interface {
	Integer | Float | ~string
}

<hr>

<sup>1: note that the package golang.org/x/exp is experimental. Its contents aren't guaranteed to be backwards compatible with new Go releases, but you can always copy-paste the definitions you need into your own code</sup>

huangapple
  • 本文由 发表于 2022年1月3日 15:05:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/70562572.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定