深入探索Go 1.21中的 maps工具库

 更新时间:2023年08月15日 10:54:16   作者:陈明勇  
随着 Go 1.21.0 版本的发布,新增了两个实用的泛型工具库:maps 和 slices,下面小编就带大家一起学习一下 maps 工具库的相关知识吧

前言

随着 Go 1.21.0 版本的发布,新增了两个实用的泛型工具库:mapsslices,它们分别提供了处理映射(map)和切片常见操作的函数,减少了我们重复造轮子的过程,提高开发效率。本文将会对 maps 工具库进行介绍。

准备好了吗?准备一杯你最喜欢的咖啡或茶,随着本文一探究竟吧。

Maps

maps 是一个泛型工具库,该库包含了对任何类型都支持的实用函数,函数简介如下表所示:

函数函数签名功能
Clonefunc Clone[M ~map[K]V, K comparable, V any](m M) M该函数返回 m 的一个副本,底层基于浅层克隆去实现,使用普通赋值的方式去设置新的键值对
Copyfunc Copy[M1 ~map[K]V, M2 ~map[K]V, K comparable, V any](dst M1, src M2)复制 src 中的所有键值对到 dst 中,如果 dst 中包含 src 中的任意 key,则该 key 对应的 value 将会被覆盖
DeleteFuncfunc DeleteFunc[M ~map[K]V, K comparable, V any](m M, del func(K, V) bool)删除 m 中满足 del 返回为 true 的任何键值对
Equalfunc Equal[M1, M2 ~map[K]V, K, V comparable](m1 M1, m2 M2) bool判断两个 map 是否包含相同的键值对,内部使用 == 进行比较
EqualFuncfunc 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 任意 keyvalue 将有可能影响原 mapvalue

我们来看下下面的例子:

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 是指针类型。从执行结果可以明显看出,如果 m1value 是指针类型,那么在对克隆后的 m2 中的任意 key 对应的 value 进行修改操作后,都会直接影响到 m1。这是因为 m1m2 共享了同一组指向相同 Programmer 结构体的指针,因此对一个指针的修改会在两个 map 中都可见。

Copy

Copy 函数接收两个 map 参数 dstsrc,该函数的功能是复制 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 变量,分别为 m1m2,然后通过 maps.Copy 函数,将 m2 中的键值对复制到 m1 中,最后打印复制后的结果。

根据结果可知,由于 m1m2 都包含 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 类型的 keyvalue 必须是 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 类型变量,分别是 m1m2m3,然后通过 maps.Equal() 函数,对 m1m2 以及 m1m3 进行等价比较。执行结果与预期一致,m1m3 是相等的,m1m2 不相等。

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 类型变量,分别是 m1m2m3。这些 map 使用 int 类型作为编号(key),User 类型作为用户信息(value)。

接着,使用 maps.EqualFunc() 函数,对 m1m2 以及 m1m3 进行等价比较,在这个函数中,我们自定义了比较函数 eq,其逻辑是只要两个 User 结构体的 IdCard 相同,就认为它们是同一个人(相等)。执行结果与预期一致,m1m3 是相等的,m1m2 不相等。

小结

本文对 Go 工具库 maps 进行详细介绍,包括其提供的函数 CloneCopyDeleteFuncEqualEqualFunc,并强调了使用这些函数时需要注意的地方。

总的来说,通过使用这些函数,减少了我们重复造轮子的过程,提高开发效率。

你使用 maps 工具库了吗?

推荐阅读

Go 1.21新内置函数min、max和clear的用法详解

到此这篇关于深入探索Go 1.21中的 maps工具库的文章就介绍到这了,更多相关Go 1.21 maps内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Go语言通过TCP协议实现聊天室功能

    Go语言通过TCP协议实现聊天室功能

    这篇文章主要为大家详细介绍了Go语言中如何通过TCP协议实现聊天室功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-04-04
  • go实现自动复制U盘小工具demo

    go实现自动复制U盘小工具demo

    这篇文章主要为大家介绍了go实现自动复制U盘小工具demo,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-12-12
  • Go中信号量的5种经典实现方式

    Go中信号量的5种经典实现方式

    本文主要介绍了Go中信号量的5种经典实现方式,可以解决高并发资源控制难题,涵盖互斥锁、通道、第三方库等实现方式,适用于限流、协程池等场景,感兴趣的可以了解一下
    2026-05-05
  • 详解Golang时间处理的踩坑及解决

    详解Golang时间处理的踩坑及解决

    在各个语言之中都有时间类型的处理,这篇文章主要和大家分享一下Golang进行时间处理时哪里最容易踩坑以及解决方法,需要的可以参考一下
    2023-01-01
  • 一步步教你打造高效可靠的Go库

    一步步教你打造高效可靠的Go库

    这篇文章主要介绍了一步步教你打造高效可靠的Go库的相关资料,需要的朋友可以参考下
    2023-11-11
  • 一文掌握gorm简介及如何使用gorm

    一文掌握gorm简介及如何使用gorm

    Gorm是一款用于Golang的ORM框架,它提供了丰富的功能,包括模型定义、数据验证、关联查询等,下面通过本文掌握gorm简介及使用方法,需要的朋友可以参考下
    2024-02-02
  • Golang的关键字defer的使用方法

    Golang的关键字defer的使用方法

    这篇文章主要介绍了Golang的关键字defer的使用方法,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-06-06
  • go语言中的面向对象

    go语言中的面向对象

    Go不支持类,而是提供了结构体。结构体中可以添加属性和方法。这样可以将数据和操作数据的方法绑定在一起,实现与类相似的效果。这篇文章介绍了go语言中的面向对象,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07
  • 一文详解Python如何处理无法解码文件名

    一文详解Python如何处理无法解码文件名

    在跨平台文件处理,国际化应用或系统管理工具开发中,文件名无法正确解码是文件名无法正确解码,本文将深入探讨Python中处理无法解码文件名的方法,大家可以根据需要进行选择
    2025-09-09
  • 使用Go语言编写简洁代码的最佳实践

    使用Go语言编写简洁代码的最佳实践

    简洁的代码对于创建可维护、可阅读和高效的软件至关重要,Go 是一种强调简单和代码整洁的语言,在本文中,我们将结合代码示例,探讨编写简洁 Go 代码的最佳实践,需要的朋友可以参考下
    2023-09-09

最新评论