写点什么

Go 泛型初体验

用户头像
Rayjun
关注
发布于: 4 小时前
Go 泛型初体验

在 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                                                                                                                                                                                                     ↵3foobar
复制代码


第一个泛型程序成功运行了。

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

发布于: 4 小时前阅读数: 2
用户头像

Rayjun

关注

程序员,王小波死忠粉 2017.10.17 加入

非著名程序员,还在学习如何写代码,公众号同名

评论

发布
暂无评论
Go 泛型初体验