go 泛型初探

go1.17于几天前正式发布, 虽然 go的泛型还没正式发布,但 go 的泛型代码已经并入 master 分支, 所以我们可以在 go1.17版本中提前试用泛型。

下载 go1.17

如果你目前没有 go 的任何版本, 你只能去官网链接下载1.17版本, 如果已有了 go 的其它版本, 你可以通过以下方式下载使用go1.17:

1
2
3
 go  get golang.org/dl/go1.17
 go1.17 download
 go1.17 version

这样就1.17就下好了。

例子

接下来我们来看看2个使用泛型的例子。

例子1:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
package main
import ("fmt")
func print[T any](s []T) {
	for _, v := range s {
		fmt.Println(v)
	}
}

func main() {
	print([]string{"Hello, ", "overstarry\n"})
	print([]int64{1, 2, 3})
	print([]float64{1, 2, 3})
}

go 使用[] 定义类型参数,与java、c++等的<>有很大不同,any关键字来表示任意类型约束。然后怎么运行呢? 简单的go run\build 是肯定不行的,要运行泛型代码,你需要在run\build 后加-G参数, 运行的命令是:

1
go1.17 run -gcflags=-G=3 main.go

img.png 可以看到,成功输出了相应的值。

接下来再来看个经典的例子, 由于go没有函数重载, 我们在写2数相加的时候,为了应对不同的类型情况,往往需要写很多不同的函数,现在来看看在泛型的情况下的add函数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
package main

import "fmt"

type Addable interface {
	type int, int8, int16, int32, int64,
		uint, uint8, uint16, uint32, uint64, uintptr,
		float32, float64, complex64, complex128
}

func add[T Addable](a, b T) T {
	return a + b
}

func main() {
	fmt.Println(add(1, 2))

	fmt.Println(add("foo", "bar"))
}

可以看到我们定义了一个 Addable 的接口, 接口定义了一系列类型,用来约束泛型函数的类型, 不在接口中的类型不能使用。

我们来运行看看吧,

img.png 可以看到,程序无法运行,提示string类型没有在接口约束中。我们加上 string 类型再试试看看,

img_1.png 这次程序顺利运行,输出了相应的值。

总结

本文主要是 go 泛型的简单初探,让我们静静等待明年2月份的 go1.18, 那时我们就能正式使用泛型了,目前的go1.17的泛型还不够完善,还存在一些问题, 如泛型函数不能导出(即首字母不能大写)。