深入探索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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • golang 字符串拼接性能的对比分析

    golang 字符串拼接性能的对比分析

    这篇文章主要介绍了golang 字符串拼接性能的对比分析,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • 解决go build不去vendor下查找包的问题

    解决go build不去vendor下查找包的问题

    这篇文章主要介绍了解决go build不去vendor下查找包的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • goland使用go mod模式的步骤详解

    goland使用go mod模式的步骤详解

    这篇文章主要介绍了goland使用go mod模式的步骤详解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-12-12
  • 模块一 GO语言基础知识-库源码文件

    模块一 GO语言基础知识-库源码文件

    这篇文章主要介绍了模块一 GO语言基础知识-库源码文件,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-01-01
  • 使用Golang搭建web服务的实现步骤

    使用Golang搭建web服务的实现步骤

    本文主要介绍了使用Golang搭建web服务的实现步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-04-04
  • 使用Go语言提高图片分辨率的方法与实践

    使用Go语言提高图片分辨率的方法与实践

    在图像处理和计算机视觉领域,提高图片分辨率是一个常见的问题,随着高分辨率显示设备的普及,如4K、8K电视以及高像素手机摄像头的应用,用户对高质量图片的需求也越来越高,本文将介绍使用Golang语言提高图片分辨率的方法与实践,需要的朋友可以参考下
    2023-12-12
  • golang中使用proto3协议导致的空值字段不显示的问题处理方案

    golang中使用proto3协议导致的空值字段不显示的问题处理方案

    这篇文章主要介绍了golang中使用proto3协议导致的空值字段不显示的问题处理方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-10-10
  • Go interface 接口的最佳实践经验分享

    Go interface 接口的最佳实践经验分享

    go 的接口在go的编程里面用的十分频繁,尤其是空接口的使用,因为有了接口,才使得Go语言变得异常的强大,今天给大家介绍下Go interface 接口的最佳实践经验分享,感兴趣的朋友一起看看吧
    2022-04-04
  • logrus hook输出日志到本地磁盘的操作

    logrus hook输出日志到本地磁盘的操作

    这篇文章主要介绍了logrus hook输出日志到本地磁盘的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-11-11
  • 对Golang import 导入包语法详解

    对Golang import 导入包语法详解

    今天小编就为大家分享一篇对Golang import 导入包语法详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-06-06

最新评论