什么是泛型
首先来说说什么是泛型,泛型其实是一个很宽泛的概念。本文中的泛型特指计算机编程语言中的泛型, 即编程语言中的函数,方法,类定义等与特定的类型参数无关,相关的函数,方法和类的实例化是根据具体的调用参数来进行。泛型是和编译紧密相关的技术,尤其是针对 golang 这种静态类型的语言来说,更是如此。
为什么要实现泛型
作为一种提高编程效能的基本范式,目前市面上主流的编程语言都已经早早支持了泛型,比如 C++ 的 template, Java 的类型擦除技术等,其主要目的都是为了最大限度的避免重复代码,利用编译器来做类型检查,避免额外的装箱/拆箱等操作,来提高程序的性能。泛型最常用的地方就是集合类库,使得集合类针对不同的类型能够复用,并且最大化开发者的费效比,减少维护成本。
泛型可以为我们提供强大的构建块,让我们可以更轻松地共享代码和构建程序。泛型编程意味着编写函数和数据结构,其中一些类型留待以后指定。例如,我们可以编写一个对某种任意数据类型的切片进行操作的函数,其中实际数据类型仅在调用该函数时指定。或者,您可以定义存储任何类型值的数据结构,在创建数据结构的实例时指定要存储的实际类型。
Golang 泛型现状
go1.17之前,社区之前也有很多的努力和尝试,包括各种泛型提案和实现方式,但最后都被否决了。
Golang 核心作者给出的解释是泛型并不是不可或缺的特性。属于重要但不紧急,应该把精力集中在更重要的事情上,例如 GC 的延迟优化,编译器自举等。
go1.17中接受了社区的提议,具体细节在这/golang/go/issues/43651
go1.18beta 于 2021年12月15日发布,引入了泛型。1.18正式版本计划2022年2月发布。
go 1.18beta1是第一个包含Go对使用参数化类型的泛型代码的新支持。从Go 1 发布以来,泛型是Go最重要的变化,也是版本之后给你带来的最大的单一语言更改。
golang 泛型示例
环境准备
安装go1.18beta1,下载地址: /dl/。
安装后同步设置环境变量 GOROOT,GOBIN。
通过内置的约束来实现
使用any约束,实现一个简单的函数:
func Print[T any](s []T) {
for _, v := range s {
(v)
}
}
这里的[T any]即为类型参数,意思是该函数支持任何类型的 slice 。但是在调用该函数的时候,需要显式指定类型参数类型。类型在调用出需要显式指定,以便编译器可以推断出实际的类型。
Print([]string{"Hello, ", "World\n"})
显式指定类型调用:
Print[string]([]string{"One, ", "Two\n"})
使用 comparable 约束类型。 comparable 是一个编译器内置的特定的扩展接口类型,该类型必须支持“==“ 方法。
使用comparable约束实现Sum:
func SumIntsOrFloats[K comparable, V int | float64](m map[K]V) V {
var s V
for _, v := range m {
s += v
}
return s
}
对其调用:
ints := map[string]int{
"first": 34,
"second": 12,
}
floats := map[string]float64{
"first": 35.98,