背景

Go官方团队在Go 1.18 Beta 1版本的标准库里因为泛型设计而引入了contraints包。

constraints包里定义了SignedUnsigned, Integer, Float, ComplexOrdered共6个interface类型,可以用于泛型里的类型约束(type constraint)。

比如我们可以用constraints包写出如下泛型代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// test.go
package main

import (
	"constraints"
	"fmt"
)

// return the min value
func min[T constraints.Ordered](a, b T) T {
	fmt.Printf("%T ", a)
	if a < b {
		return a
	}
	return b
}

func main() {
	minInt := min(1, 2)
	fmt.Println(minInt)

	minFloat := min(1.0, 2.0)
	fmt.Println(minFloat)

	minStr := min("a", "b")
	fmt.Println(minStr)
}

函数min是一个泛型函数,接收2个参数,返回其中的较小者。

类型参数T的类型约束contraints.Ordered的定义如下:

1
2
3
type Ordered interface {
	Integer | Float | ~string
}

上面代码的执行结果为:

1
2
3
int 1
float64 1
string a

备注:如果对Go泛型和constraints包还不太了解的同学,可以翻看我之前写的一文读懂Go泛型设计和使用场景

现状

Go官方团队的技术负责人Russ Cox在2022.01.25提议constraints包从Go标准库里移除,放到x/exp项目下。Russ Cox给出的理由如下:

There are still questions about the the constraints package. To start with, although many people are happy with the name, many are not. On top of that, it is unclear exactly which interfaces are important and should be present and which should be not. More generally, all the considerations that led us to move slices and maps to x/exp apply to constraints as well.

We left constraints behind in the standard library because we believed it was fundamental to using generics, but in practice that hasn’t proven to be the case. In particular, most code uses any or comparable. If those are the only common constraints, maybe we don’t need the package. Or if constraints.Ordered is the only other commonly used constraint, maybe that should be a predeclared identifier next to any and comparable. The ability to abbreviate simple constraints let us remove constraints.Chan, constraints.Map, and constraints.Slice, which probably would have been commonly used, but they’re gone.

Unlike other interfaces like, say, context.Context, there is no compatibility issue with having a constraint interface defined in multiple packages. The problems that happen with duplicate interfaces involve other types built using that type, such as func(context.Context) vs func(othercontext.Context). But that cannot happen with constraints, because they can only appear as type parameters, and they are irrelevant to type equality for a particular substitution. So having x/exp/constraints and later having constraints does not cause any kind of migration problem at all, unlike what happened with context.

For all these reasons, it probably makes sense to move constraints to x/exp along with slices and maps for Go 1.18 and then revisit it in the Go 1.19 or maybe Go 1.20 cycle. (Realistically, we may not know much more for Go 1.19 than we do now.)

Discussed with @robpike, @griesemer, and @ianlancetaylor, who all agree.

该提议也同Go语言发明者Rob Pike, Robert Griesemer和Ian Lance Taylor做过讨论,得到了他们的同意。

其中Robert Griesemer和Ian Lance Taylor是Go泛型的设计者。

Russ Cox将这个提议在GitHub公布后,社区成员没有反对意见,因此在2022.02.03这个提议得到正式通过。

不过值得注意的是,2022.01.31发布的Go 1.18 Beta 2版本里还保留了constraints包,不建议大家再去使用。

备注:

  • golang.org/x下所有package的源码独立于Go源码的主干分支,也不在Go的二进制安装包里。如果需要使用golang.org/x下的package,可以使用go get来安装。
  • golang.org/x/exp下的所有package都属于实验性质或者被废弃的package,不建议使用。

移除原因

支持泛型的Go 1.18 Beta 1版本发布以来,围绕着constraints包的争议很多。

主要是以下因素,导致Russ Cox决定从Go标准库中移除constraints包。

  • constraints名字太长,代码写起来比较繁琐。
  • 大多数泛型的代码只用到了anycomparable这2个类型约束。constaints包里只有constraints.Ordered使用比较广泛,其它很少用。所以完全可以把Ordered设计成和any以及comparable一样,都作为Go的预声明标识符,不用单独弄一个constraints包。

总结

建议不要使用constraints包,毕竟Go 1.18正式版本会去掉。

我写了2篇Go泛型入门的教程,欢迎大家参考

好文推荐

开源地址

文章和示例代码开源在GitHub: Go语言初级、中级和高级教程

公众号:coding进阶。关注公众号可以获取最新Go面试题和技术栈。

个人网站:Jincheng’s Blog

知乎:无忌

References