阅读 395
Go 泛型初体验

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                                                                                                                                                                                                     ↵
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 泛型目前还没有正式发布,上面的内容在正式发布的时候可能也会有所调整,所以不要在生产中区使用泛型。

本文例子来源于:github.com/mattn/go-ge…

文 / Rayjun

文章分类
后端
文章标签