尝鲜Go范型版本的map和slice

本文首发于 https://robberphex.com/go-generics-maps-slices/


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

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

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

go-generic-exp-module.png

大家也可以读一下对应的代码: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版本正式发布:

golang-nightly-image.png

那么我们就可以用如下命令启动一个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"
# ./m
m1 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?	 true
m2==m2?	 true
m1==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"
# ./m
s1==s1?	 true
s2==s2?	 true
s1==s2?	 true
s1[1]=2
s1[-1]=999

总结

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

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

本站文章资源均来源自网络,除非特别声明,否则均不代表站方观点,并仅供查阅,不作为任何参考依据!
如有侵权请及时跟我们联系,本站将及时删除!
如遇版权问题,请查看 本站版权声明
THE END
分享
二维码
海报
尝鲜Go范型版本的map和slice
本文首发于 https://robberphex.com/go-generics-maps-slices/
<<上一篇
下一篇>>