写点什么

尝鲜 Go 1.18 中范型版本的 map 和 slice

作者:Robert Lu
  • 2021 年 12 月 12 日
  • 本文字数:1621 字

    阅读完需:约 5 分钟

大家最近都关注到了 Go 1.18 会支持范型的消息了吧。


作为 Golang 的内置类型,大家都期待 map 和 slice 支持范型后,可以简化很多的判断逻辑,比如 Equal 逻辑等等。


几天前,Go 范型的标准库已经提交了,且可以试用了:



大家也可以读一下对应的代码:https://cs.opensource.google/go/x/exp/+/master:maps/maps.go


废话不多说,我们看下如何尝试范型版本的 map 和 slice 吧!

如何使用 Go 1.18?

Golang 官网链接只有 1.17 版本的下载,那么我们如何才能使用 1.18 版本的 Golang 呢?


网上翻了翻,有人提供了 Golang 1.18 版本的 Docker 镜像 seongwoohong/golang-nightly:1.18,而且保证维护到 1.18 版本正式发布:



那么我们就可以用如下命令启动一个 go1.18 的编译环境了:


$ docker run --rm -it -v $PWD:/root/go-generics seongwoohong/golang-nightly:1.18 sh# cd /root/go-generics/~/go-generics #
复制代码

尝试 maps

翻了下 maps 的代码和测试用例,用下面的代码演示下 maps 的功能:


package main
import ( "fmt" "strconv"
"golang.org/x/exp/maps" // v0.0.0-20211129234152-8a230f1f7d7a)
func main() { var m1 = map[int]int{1: 2, 2: 4, 4: 8, 8: 16} var m2 = map[string]string{"1": "2", "2": "4", "4": "8", "8": "16"} var m3 = map[int]string{1: "2", 2: "4", 4: "8", 8: "16"}
// Keys 方法返回map的所有键 // 如果没有范型,那么对于每种map,都需要写Keys方法,现在只需要一个 fmt.Printf("m1 Keys:\t%#v\n", maps.Keys(m1)) fmt.Printf("m2 Kyes:\t%#v\n", maps.Keys(m2))
// Values 方法返回map的所有值 fmt.Printf("m1 Values:\t%#v\n", maps.Values(m1)) fmt.Printf("m2 Values:\t%#v\n", maps.Values(m2))
// 判断map是否相等 fmt.Println("m1==m1?\t", maps.Equal(m1, m1)) fmt.Println("m2==m2?\t", maps.Equal(m2, m2)) //fmt.Println(maps.Equal(m1, m2)) // map[int]int与map[string]string无法比较
// 判断map是否相等(手动指定判断逻辑) fmt.Println("m1==m3?\t", maps.EqualFunc(m1, m3, func(v1 int, v2 string) bool { return strconv.Itoa(v1) == v2 }))
// 还有一些Clear、Clone、Copy、DeleteFunc,都是见名知义的函数}
复制代码


然后编译执行看看:


# go build -gcflags="-G=3 -lang=go1.18"# ./mm1 Keys:  []int{1, 2, 4, 8}m2 Kyes:  []string{"8", "1", "2", "4"}m1 Values:  []int{2, 4, 8, 16}m2 Values:  []string{"16", "2", "4", "8"}m1==m1?   truem2==m2?   truem1==m3?   true
复制代码

尝试 slices

同样,翻翻 slices 的代码和测试用例,可以用下面的代码演示下 slices 的功能:


package main
import ( "fmt" "strconv"
"golang.org/x/exp/slices" // v0.0.0-20211129234152-8a230f1f7d7a)
func main() { var s1 = []int{1, 2, 3} var s2 = []string{"1", "2", "3"}
// 判断slice是否相等 fmt.Println("s1==s1?\t", slices.Equal(s1, s1)) fmt.Println("s2==s2?\t", slices.Equal(s2, s2)) //fmt.Println(slices.Equal(s1, s2)) //[]int与[]string无法比较
// 判断slice是否相等(手动指定判断逻辑) fmt.Println("s1==s2?\t", slices.EqualFunc(s1, s2, func(v1 int, v2 string) bool { return strconv.Itoa(v1) == v2 }))
// 在slice中查找某个元素 fmt.Printf("s1[%v]=%d\n", slices.Index(s1, 2), 2) fmt.Printf("s1[%v]=%d\n", slices.Index(s1, 999), 999)
// 还有一些Clear、Clone、Copy、DeleteFunc,都是见名知义的函数}
复制代码


同样可以编译通过并执行:


# go build -gcflags="-G=3 -lang=go1.18"# ./ms1==s1?   trues2==s2?   trues1==s2?   trues1[1]=2s1[-1]=999
复制代码

总结

相比于 Java 的范型,Golang 真正做到了运行时的范型,能够提升一些效率。


更重要的是,就像王垠之前吐槽的那样,Java的数组不支持范型,这让Java的类型系统显得不是那么完备。在这一点上,Golang 做的更好些。

用户头像

Robert Lu

关注

还未添加个人签名 2015.04.06 加入

阿里云高级开发工程师

评论

发布
暂无评论
尝鲜Go 1.18中范型版本的map和slice