开始尝鲜Go范型版本的map和slice

简介: 手把手教你尝试Go范型

本文首发于 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做的更好些。

相关文章
|
11月前
|
Go
go语言中遍历映射(map)
go语言中遍历映射(map)
242 8
|
3月前
|
存储 人工智能 安全
深入理解 go sync.Map - 基本原理
本文介绍了 Go 语言中 `map` 在并发使用时的常见问题及其解决方案,重点对比了 `sync.Mutex`、`sync.RWMutex` 和 `sync.Map` 的性能差异及适用场景。文章指出,普通 `map` 不支持并发读写,容易引发错误;而 `sync.Map` 通过原子操作和优化设计,在某些场景下能显著提升性能。同时详细讲解了 `sync.Map` 的基本用法及其适合的应用环境,如读多写少或不同 goroutine 操作不同键的场景。
156 1
|
5月前
|
存储 安全 Go
Map的遍历与判断键是否存在-《Go语言实战指南》
本文介绍了 Go 语言中对 `map` 的常见操作,包括遍历所有项和判断键是否存在。通过 `for range` 可以遍历 `map` 的键值对、仅键或仅值(需忽略键)。注意,`map` 遍历顺序是随机的。判断键是否存在时,使用双赋值语法 `value, ok := map[key]`,其中 `ok` 表示键是否存在。直接访问不存在的键会返回类型的零值,可能导致逻辑错误。掌握这些机制可更安全高效地处理键值对数据。
|
5月前
|
人工智能 Go
[go]Slice 切片原理
本文详细介绍了Go语言中的切片(slice)数据结构,包括其定义、创建方式、扩容机制及常见操作。切片是一种动态数组,依托底层数组实现,具有灵活的扩容和传递特性。文章解析了切片的内部结构(包含指向底层数组的指针、长度和容量),并探讨了通过`make`创建切片、基于数组生成切片以及切片扩容的规则。此外,还分析了`append`函数的工作原理及其可能引发的扩容问题,以及切片拷贝时需要注意的细节。最后,通过典型面试题深入讲解了切片在函数间传递时的行为特点,帮助读者更好地理解和使用Go语言中的切片。
123 0
|
8月前
|
存储 缓存 安全
Go 语言中的 Sync.Map 详解:并发安全的 Map 实现
`sync.Map` 是 Go 语言中用于并发安全操作的 Map 实现,适用于读多写少的场景。它通过两个底层 Map(`read` 和 `dirty`)实现读写分离,提供高效的读性能。主要方法包括 `Store`、`Load`、`Delete` 等。在大量写入时性能可能下降,需谨慎选择使用场景。
|
9月前
|
存储 安全 Go
Go语言中的map数据结构是如何实现的?
Go 语言中的 `map` 是基于哈希表实现的键值对数据结构,支持快速查找、插入和删除操作。其原理涉及哈希函数、桶(Bucket)、动态扩容和哈希冲突处理等关键机制,平均时间复杂度为 O(1)。为了确保线程安全,Go 提供了 `sync.Map` 类型,通过分段锁实现并发访问的安全性。示例代码展示了如何使用自定义结构体和切片模拟 `map` 功能,以及如何使用 `sync.Map` 进行线程安全的操作。
248 9
|
10月前
|
Go
go语言for遍历映射(map)
go语言for遍历映射(map)
349 12
|
11月前
|
存储 Go
go语言 遍历映射(map)
go语言 遍历映射(map)
278 2
|
Go 定位技术 索引
Go 语言Map(集合) | 19
Go 语言Map(集合) | 19
|
Go
Go 语言学习之map
Go 语言学习之map
110 0

热门文章

最新文章