为什么要使用泛型?
但是添加泛型意味着什么,为什么我们要它呢?

用Jazayeri等人的话来解释 :泛型编程可以用泛型形式表示功能和数据结构,而类型被排除在外。

那是什么意思?

举一个简单的例子,假设我们要反转切片中的元素。这不是许多程序需要做的事情,但这并不是那么寻常。

假设这是int的一部分。

func ReverseInts(s []int) {
first := 0
last := len(s)
for first < last {
s[first], s[last] = s[last], s[first]
first++
last--
}
}
非常简单,但是即使对于这样的简单功能,您也要编写一些测试用例。实际上,当我这样做时,我发现了一个错误。我相信很多读者已经发现它了。

func ReverseInts(s []int) {
first := 0
last := len(s) - 1
for first < last {
s[first], s[last] = s[last], s[first]
first++
last--
}
}
最后设置变量时需要减去1。

现在,让我们反转一个字符串片段。

func ReverseStrings(s []string) {
first := 0
last := len(s) - 1
for first < last {
s[first], s[last] = s[last], s[first]
first++
last--
}
}
如果比较ReverseInts和ReverseStrings,则将看到两个函数完全相同,除了参数的类型不同。我认为任何读者都不会对此感到惊讶。

Go的新手感到惊讶的是,没有办法编写Reverse适用于任何类型切片的简单函数。

大多数其他语言的确可以让您编写这种功能。

在动态类型的语言(如Python或JavaScript)中,您可以简单地编写函数,而不必费心指定元素类型。这在Go中不起作用,因为Go是静态类型的,并且要求您写下分片的确切类型和分片元素的类型。

大多数其他静态类型的语言,例如C ++或Java或Rust或Swift,都支持泛型来解决此类问题。

立即进行通用编程
那么人们如何在Go中编写此类代码?

在Go中,您可以通过使用接口类型并在要传递的切片类型上定义一个方法来编写一个适用于不同切片类型的单个函数。这就是标准库sort.Sort函数的工作方式。

换句话说,Go中的接口类型是通用编程的一种形式。它们让我们捕获了不同类型的共同方面,并将它们表达为方法。然后,我们可以编写使用这些接口类型的函数,并且这些函数将对实现那些方法的任何类型起作用。

但是这种方法达不到我们想要的。使用接口,您必须自己编写方法。必须使用几个方法来定义一个命名类型来反转切片是很尴尬的。而且对于每种切片类型,您编写的方法完全相同,因此从某种意义上说,我们只是移动并压缩了重复的代码,我们并未消除它。尽管接口是泛型的一种形式,但它们并不能满足我们对泛型的所有需求。

使用泛型接口的另一种方法可以解决需要自己编写方法的麻烦,那就是让语言为某些类型定义方法。该语言今天不支持这种功能,但是例如,该语言可以定义每个切片类型都有一个返回元素的Index方法。但是,为了在实践中使用该方法,必须返回一个空的接口类型,然后我们将失去静态类型的所有好处。更巧妙地讲,将无法定义一个通用函数,该通用函数采用具有相同元素类型的两个不同切片,或者采用一种元素类型的映射并返回相同元素类型的切片。Go是一种静态类型的语言,因为它可以简化编写大型程序的过程。

另一种方法是Reverse使用reflect包编写通用函数,但是编写起来很尴尬,而且运行起来很慢,很少有人这样做。该方法还需要显式类型声明,并且没有静态类型检查。

或者,您可以编写一个代码生成器,该代码生成器接受一个类型并Reverse为该类型的切片生成一个 函数。有几个代码生成器可以做到这一点。但这给需要的每个程序包又增加了一步Reverse,这使构建变得复杂,因为必须编译所有不同的副本,并且要修复主源中的错误,需要重新生成所有实例,其中某些实例可能完全在不同的项目中。

所有这些方法都非常笨拙,以至于我认为大多数必须在Go中反转切片的人都只是为他们所需的特定切片类型编写函数。然后,他们需要为该函数编写测试用例,以确保它们不会像我最初犯的那样犯一个简单的错误。他们将需要定期运行这些测试。

但是,我们这样做,就意味着除了元素类型外,对于一个看起来完全相同的函数,这意味着需要做很多额外的工作。不是说它不能完成。显然,这是可以做到的,Go程序员正在这样做。只是应该有一个更好的方法。

对于像Go这样的静态类型的语言,更好的方法是泛型。我之前写的是,泛型编程支持以泛型形式表示功能和数据结构,而类型被排除在外。这正是我们想要的。