深入探索Go 1.21中的 maps工具库
前言
随着 Go 1.21.0
版本的发布,新增了两个实用的泛型工具库:maps
和 slices
,它们分别提供了处理映射(map
)和切片常见操作的函数,减少了我们重复造轮子的过程,提高开发效率。本文将会对 maps
工具库进行介绍。
准备好了吗?准备一杯你最喜欢的咖啡或茶,随着本文一探究竟吧。
Maps
maps
是一个泛型工具库,该库包含了对任何类型都支持的实用函数,函数简介如下表所示:
函数 | 函数签名 | 功能 |
---|---|---|
Clone | func Clone[M ~map[K]V, K comparable, V any](m M) M | 该函数返回 m 的一个副本,底层基于浅层克隆去实现,使用普通赋值的方式去设置新的键值对 |
Copy | func Copy[M1 ~map[K]V, M2 ~map[K]V, K comparable, V any](dst M1, src M2) | 复制 src 中的所有键值对到 dst 中,如果 dst 中包含 src 中的任意 key,则该 key 对应的 value 将会被覆盖 |
DeleteFunc | func DeleteFunc[M ~map[K]V, K comparable, V any](m M, del func(K, V) bool) | 删除 m 中满足 del 返回为 true 的任何键值对 |
Equal | func Equal[M1, M2 ~map[K]V, K, V comparable](m1 M1, m2 M2) bool | 判断两个 map 是否包含相同的键值对,内部使用 == 进行比较 |
EqualFunc | func EqualFunc[M1 ~map[K]V1, M2 ~map[K]V2, K comparable, V1, V2 any](m1 M1, m2 M2, eq func(V1, V2) bool) bool | 类似 Equal 函数,但通过 eq 函数进行比较值,键仍使用 == 进行比较 |
Clone
Clone
函数接收一个 m
参数,该函数的功能是返回 m
的副本,底层基于浅层克隆去实现,使用普通赋值的方式去设置新的键值对。
代码示例:
package main import ( "fmt" "maps" ) func main() { type Programmer struct { Name string City string } m1 := map[string]Programmer{ "programmer-01": {Name: "陈明勇", City: "深圳"}, "programmer-02": {Name: "张三", City: "广州"}, } m2 := maps.Clone(m1) fmt.Printf("m1: %v\n", m1) fmt.Printf("m2: %v\n", m2) }
执行结果:
m1: map[programmer-01:{陈明勇 深圳} programmer-02:{张三 广州}]
m2: map[programmer-01:{陈明勇 深圳} programmer-02:{张三 广州}]
上述例子中,首先创建一个 map
类型的变量 m1
,然后通过 maps.Clone()
函数进行克隆,得到 m2
,最后通过打印结果可知 m2
的值和 m1
的值一样。
从函数的功能描述中可知,Clone
函数的原理是浅层克隆,那么修改克隆后的 map
任意 key
的 value
将有可能影响原 map
的 value
。
我们来看下下面的例子:
package main import ( "fmt" "maps" ) func main() { type Programmer struct { Name string City string } m1 := map[string]*Programmer{ "programmer-01": {Name: "陈明勇", City: "深圳"}, "programmer-02": {Name: "张三", City: "广州"}, } fmt.Printf("m1: %v, %v\n", *m1["programmer-01"], *m1["programmer-02"]) m2 := maps.Clone(m1) fmt.Printf("m2: %v, %v\n", *m2["programmer-01"], *m2["programmer-02"]) m2["programmer-02"].City = "海口" fmt.Printf("m2 被修改后,m1: %v, %v\n", *m1["programmer-01"], *m1["programmer-02"]) fmt.Printf("m2 被修改后,m2: %v, %v\n", *m2["programmer-01"], *m2["programmer-02"]) }
执行结果
m1: {陈明勇 深圳}, {张三 广州}
m2: {陈明勇 深圳}, {张三 广州}
m2 被修改后,m1: {陈明勇 深圳}, {张三 海口}
m2 被修改后,m2: {陈明勇 深圳}, {张三 海口}
与前面的示例不同,这个例子中的一个关键区别在于 value
是指针类型。从执行结果可以明显看出,如果 m1
的 value
是指针类型,那么在对克隆后的 m2
中的任意 key
对应的 value
进行修改操作后,都会直接影响到 m1
。这是因为 m1
和 m2
共享了同一组指向相同 Programmer
结构体的指针,因此对一个指针的修改会在两个 map
中都可见。
Copy
Copy
函数接收两个 map
参数 dst
和 src
,该函数的功能是复制 src
中的所有键值对到 dst
中,如果 dst
中包含 src
中的任意 key
,则该 key
对应的 value
将会被覆盖。
代码示例:
package main import ( "fmt" "maps" ) func main() { m1 := map[string]string{"Name": "陈明勇", "City": "深圳"} m2 := map[string]string{"City": "广州", "Phone": "123456789"} maps.Copy(m1, m2) fmt.Println(m1) }
执行结果:
map[City:广州 Name:陈明勇 Phone:123456789]
在上述例子中,首先创建了两个 map
变量,分别为 m1
和 m2
,然后通过 maps.Copy
函数,将 m2
中的键值对复制到 m1
中,最后打印复制后的结果。
根据结果可知,由于 m1
和 m2
都包含 key → City
,因此在执行复制操作后, m1
中的 key → City
对应的 value
值会被覆盖。
DeleteFunc
DeleteFunc
函数接收一个 map
类型的参数 m
和一个函数类型的参数 del
。该函数的功能是删除 m
中满足 del
返回为 true
的任何键值对。
代码示例:
package main import ( "fmt" "maps" ) func main() { m1 := map[int]string{1: "陈明勇", 2: "张三", 3: "李四", 4: "王五"} maps.DeleteFunc(m1, func(k int, v string) bool { return k%2 == 0 }) fmt.Println(m1) }
执行结果:
map[1:陈明勇 3:李四]
在上述例子中,首先创建了一个 map
变量 m1
,使用 int
类型作为学号(key
),string
类型作为姓名(value
),然后通过 maps.DeleteFunc
删除学号为双数的学生,匿名函数的逻辑是 当学号为双数时,返回 true。
总体来说这个例子相对简单,读者可根据实际应用场景进行使用 DeleteFunc
函数。
Equal
Equal
函数接收两个 map
变量,函数的返回值为 bool
类型。该函数的功能是判断两个 map
是否包含相同的键值对,内部使用 ==
进行比较。注意:map
类型的 key
和 value
必须是 comparable
类型。
代码示例:
package main import ( "fmt" "maps" ) func main() { m1 := map[int]int{0: 0, 1: 1, 2: 2} m2 := map[int]int{0: 0, 1: 1} m3 := map[int]int{0: 0, 1: 1, 2: 2} fmt.Println(maps.Equal(m1, m2)) // false fmt.Println(maps.Equal(m1, m3)) // true }
执行结果:
false
true
上述例子中,首先创建了三个 map
类型变量,分别是 m1
、m2
和 m3
,然后通过 maps.Equal()
函数,对 m1
和 m2
以及 m1
和 m3
进行等价比较。执行结果与预期一致,m1
和 m3
是相等的,m1
和 m2
不相等。
EqualFunc
EqualFunc
函数类似 Equal
函数,只不过是通过 eq
函数进行比较值,键仍使用 ==
进行比较。注意: value
可以为任意类型(any
)。
代码示例:
package main import ( "fmt" "maps" ) func main() { type User struct { Nickname string IdCard string } m1 := map[int]User{0: {Nickname: "陈明勇", IdCard: "111"}, 1: {Nickname: "张三", IdCard: "222"}} m2 := map[int]User{0: {Nickname: "陈明勇", IdCard: "111"}} m3 := map[int]User{0: {Nickname: "Go技术干货", IdCard: "111"}, 1: {Nickname: "张三", IdCard: "222"}} fmt.Println(maps.EqualFunc(m1, m2, func(user User, user2 User) bool { return user.IdCard == user2.IdCard })) // false fmt.Println(maps.EqualFunc(m1, m3, func(user User, user2 User) bool { return user.IdCard == user2.IdCard })) // true }
执行结果:
false
true
上述例子中,首先创建了三个 map
类型变量,分别是 m1
、m2
和 m3
。这些 map
使用 int
类型作为编号(key
),User
类型作为用户信息(value
)。
接着,使用 maps.EqualFunc()
函数,对 m1
和 m2
以及 m1
和 m3
进行等价比较,在这个函数中,我们自定义了比较函数 eq
,其逻辑是只要两个 User
结构体的 IdCard
相同,就认为它们是同一个人(相等)。执行结果与预期一致,m1
和 m3
是相等的,m1
和 m2
不相等。
小结
本文对 Go
工具库 maps
进行详细介绍,包括其提供的函数 Clone
、Copy
、DeleteFunc
、Equal
和 EqualFunc
,并强调了使用这些函数时需要注意的地方。
总的来说,通过使用这些函数,减少了我们重复造轮子的过程,提高开发效率。
你使用 maps
工具库了吗?
推荐阅读
Go 1.21新内置函数min、max和clear的用法详解
到此这篇关于深入探索Go 1.21中的 maps工具库的文章就介绍到这了,更多相关Go 1.21 maps内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
GoFrame gredis缓存DoVar及Conn连接对象的自动序列化
这篇文章主要为大家介绍了GoFrame gredis干货DoVar Conn连接对象自动序列化详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪2022-06-06Go语言动态并发控制sync.WaitGroup的灵活运用示例详解
本文将讲解 sync.WaitGroup 的使用方法、原理以及在实际项目中的应用场景,用清晰的代码示例和详细的注释,助力读者掌握并发编程中等待组的使用技巧2023-11-11
最新评论