在 Go1.17 中,千呼万唤的泛型终于出来了,但又没有完全出来。在 Go1.17 的发布文档中,并没有提到泛型,但是眼见的网友发现,泛型相关的代码其实已经合并了,只是没有默认启用。目前来说,泛型的玩玩就行,不要用到生产中。
泛型有望在 Go1.18 版本中发布。
1. 启用泛型
泛型的功能虽然添加到 Go.1.17 中了,如果要使用,需要添加一些参数开启,首先需要安装 Go1.17:
$ go version ~
go version go1.17 darwin/amd64
然后可以在编译 的参数中看到泛型的影子,下面的 -G 参数就是启用泛型所需要的参数:
$ go tool compile -h ~
usage: compile [options] file.go...
-% int
debug non-static initializers
-+ compiling runtime
-B disable bounds checking
-C disable printing of columns in error messages
-D path
set relative path for local imports
-E debug symbol export
-G accept generic code
看一个例子:
package main
import (
"fmt"
)
type Addable interface {
type int, int8, int16, int32, int64,
uint, uint8, uint16, uint32, uint64, uintptr,
float32, float64, complex64, complex128,
string
}
func add[T Addable](a, b T) T {
return a + b
}
func main() {
fmt.Println(add(1,2))
fmt.Println(add("foo","bar"))
}
如果直接运行上面的代码,会报下面的错误,这也说明 Go1.17 默认是不支持泛型的:
$ go run main.go
# command-line-arguments
./main.go:8:2: syntax error: unexpected type, expecting method or interface name
./main.go:14:6: missing function body
./main.go:14:9: syntax error: unexpected [, expecting (
需要加上下面的参数:
$ go run -gcflags=-G=3 main.go ↵
3
foobar
第一个泛型程序成功运行了。
2. 类型参数和约束
在 Go 泛型中,增加了两个新概念,一个是 type parameters,下面代码中的 T 就是类型参数,用来表示泛型:
func add[T Addable](a, b T) T {
return a + b
}
可以说 type parameters 在 Go 中就是泛型的意思。
再看一下下面这段代码,这里泛型的类型是 any,上面的代码则是自定义的 Addable。
func print[T any](a T) {
fmt.Printf("%v", a)
}
上面的 add 函数是有约束的,只能使用 Addable 中定义的类型,如果我们把 Addable 中的 string 去掉,代码就会报下面的错误:
$ go run -gcflags=-G=3 main.go
# command-line-arguments
./main.go:24:20: string does not satisfy Addable (string not found in int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr, float32, float64, complex64, complex128)
而 print 函数则可以接受任何类型的参数。
这就是 Go 中泛型最重要的两个概念:类型参数 和 约束。
3. 类型推断
正常使用泛型的时候,其实要使用下面这种方式来调用的,以 add 方法为例:
add[int](1,2)
add[string]("foo","bar")
但是按照下面的方式写代码也是合法的:
add(1,2)
add("foo","bar")
可以把泛型参数省略调,这不部分的工作其实是 Go 编译器来完成的,编译器会根据传入的实际类型来推断,而不用每次写代码的时候都指明泛型的类型。
类型推断可以让代码简洁不少。
4. 小结
Go 泛型涉及到的内容大致就是上面这些了,当然泛型也可以写出很复杂的代码,但实际上涉及到的内容也就是上面那些。总体来说还是比较简洁的,这也与 Go 的设计理念符合。
Go 泛型目前还没有正式发布,上面的内容在正式发布的时候可能也会有所调整,所以不要在生产中区使用泛型。
本文例子来源于:https://github.com/mattn/go-generics-example
文 / Rayjun