golang|Go 泛型的使用

Go 1.18 Beta 1版本发布泛型
2021年12月14日 Go 1.18 Beta 1版本发布,带来了大家争议已久的泛型。
已经过去几天了,今天趁周末体验了下go泛型的使用,下面给大家介绍一下,demo是官方提供的。
首先要把go的版本升级为Go 1.18 Beta 1

Administrator@20201002-163950 MINGW64 ~/Desktop $ go get golang.org/dl/go1.18beta1@latest go: finding golang.org/dl latest go: downloading golang.org/dl v0.0.0-20211214194107-65ed43b8dfff go: extracting golang.org/dl v0.0.0-20211214194107-65ed43b8dfffAdministrator@20201002-163950 MINGW64 ~/Desktop $ go1.18beta1 download Downloaded0.0% (16384 / 157362450 bytes) ... Downloaded5.0% (7946192 / 157362450 bytes) ... Downloaded20.7% ( 32554768 / 157362450 bytes) ... Downloaded36.3% ( 57114192 / 157362450 bytes) ... Downloaded51.9% ( 81640864 / 157362450 bytes) ... Downloaded67.5% (106282208 / 157362450 bytes) ... Downloaded77.3% (121650272 / 157362450 bytes) ... Downloaded84.2% (132512784 / 157362450 bytes) ... Downloaded99.9% (157170528 / 157362450 bytes) ... Downloaded 100.0% (157362450 / 157362450 bytes) Unpacking C:\Users\Administrator\sdk\go1.18beta1\go1.18beta1.windows-amd64.zip ... Success. You may now run 'go1.18beta1'Administrator@20201002-163950 MINGW64 ~/Desktop $ alias go=go1.18beta1Administrator@20201002-163950 MINGW64 ~/Desktop $ go version go version go1.18beta1 windows/amd64

泛型初体验 SumIntsOrFloats函数:
  • SumIntsOrFloats这个函数有两个类型形参K和V,还有一个使用类型形参的参数,类型是map[K]V的m。函数的返回值类型是V。
  • 方括号内的K参数是什么意思呢?大家都知道map的key对类型有一定要求,所以这里K的类型参数为comparable类型,comparable是在Go中已经声明过的,这个类型是一个可以比较的类型,通俗来讲就是允许使用 == 和 !=进行值比较的类型,comparable接口满足go对map的key的要求。
  • V类型参数也指定了一个类型约束,该约束是两种类型的联合:int64和float64,使用|指定两种类型的并集,这样就代表int64和float64都被允许作为V的实参调用这个SumIntsOrFloats函数。
    指定m参数的类型为map[K]V,其中K和V是已经为类型参数指定的类型。
mian函数:
  • 在这里调用刚才的SumIntsOrFloats函数,首先要传入类型参数,然后再传入实参,调用参数的时候按指定的类型参数将函数内的类型做替换。
func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V { var s V for _, v := range m { s += v } return s }func main() { // Initialize a map for the integer values ints := map[string]int64{ "first": 34, "second": 12, } // Initialize a map for the float values floats := map[string]float64{ "first": 35.98, "second": 26.99, } fmt.Printf("Generic Sums111: %v and %v\n", SumIntsOrFloats[string, int64](ints), SumIntsOrFloats[string, float64](floats)) }

省略类型参数的写法 大家再来看一下下面的写法,这里调用泛型函数的时候省略了类型参数,这时编译器从函数实参的类型中推断类型参数。
func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V { var s V for _, v := range m { s += v } return s }func main() { // Initialize a map for the integer values ints := map[string]int64{ "first": 34, "second": 12, } // Initialize a map for the float values floats := map[string]float64{ "first": 35.98, "second": 26.99, } fmt.Printf("Generic Sums, type parameters inferred: %v and %v\n", SumIntsOrFloats(ints), SumIntsOrFloats(floats)) }

接口类型约束 官方还提供了一个更为简单的约束类型的方法,可以事先声明一种接口类型作为类型约束,这样可以事先多个函数的复用。
Number:
  • 这个接口声明了一个int64和float64的联合,当想要类型约束为int64或float64的时候,可以直接使用这个Number类型约束,而不是再写一遍int64 | float64。
SumNumbers:
  • 这个函数的逻辑和前面一样,但是使用的是接口类型作为类型约束,而不是联合类型。
【golang|Go 泛型的使用】main:
  • 这里同样可以在调用泛型函数的时候省略类型参数
type Number interface { int64 | float64 }func SumNumbers[K comparable, V Number](m map[K]V) V { var s V for _, v := range m { s += v } return s }func main() { // Initialize a map for the integer values ints := map[string]int64{ "first": 34, "second": 12, } // Initialize a map for the float values floats := map[string]float64{ "first": 35.01, "second": 26.99, } fmt.Printf("Generic Sums with Constraint: %v and %v\n", SumNumbers(ints), SumNumbers(floats)) }

    推荐阅读