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

简介: 本文对 Go 工具库 maps 进行详细介绍,包括其提供的函数 Clone、Copy、DeleteFunc、Equal 和 EqualFunc,并强调了使用这些函数时需要注意的地方。
Go 版本:1.21.0

前言

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

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

Maps

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

函数 函数签名 功能
Clone func Clone[M ~map[K]V, K comparable, V any] M 该函数返回 m 的一个副本,底层基于浅层克隆去实现,使用普通赋值的方式去设置新的键值对
Copy func Copy[M1 ~map[K]V, M2 ~map[K]V, K comparable, V any] 复制 src 中的所有键值对到 dst 中,如果 dst 中包含 src 中的任意 key,则该 key 对应的 value 将会被覆盖
DeleteFunc func DeleteFunc[M ~map[K]V, K comparable, V any] func(K, V) bool) 删除 m 中满足 del 返回为 true 的任何键值对
Equal func Equal[M1, M2 ~map[K]V, K, V comparable] bool 判断两个 map 是否包含相同的键值对,内部使用 == 进行比较
EqualFunc func EqualFunc[M1 ~map[K]V1, M2 ~map[K]V2, K comparable, V1, V2 any]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 工具库了吗?感受如何,欢迎留言探讨。

目录
相关文章
|
5月前
|
Shell Go API
Go语言grequests库并发请求的实战案例
Go语言grequests库并发请求的实战案例
|
3月前
|
JSON Go 开发者
go-carbon v2.5.0 发布,轻量级、语义化、对开发者友好的 golang 时间处理库
carbon 是一个轻量级、语义化、对开发者友好的 Golang 时间处理库,提供了对时间穿越、时间差值、时间极值、时间判断、星座、星座、农历、儒略日 / 简化儒略日、波斯历 / 伊朗历的支持。
62 4
|
3月前
|
存储 Cloud Native Shell
go库介绍:Golang中的Viper库
Viper 是 Golang 中的一个强大配置管理库,支持环境变量、命令行参数、远程配置等多种配置来源。本文详细介绍了 Viper 的核心特点、应用场景及使用方法,并通过示例展示了其强大功能。无论是简单的 CLI 工具还是复杂的分布式系统,Viper 都能提供优雅的配置管理方案。
|
3月前
|
JSON 安全 网络协议
go语言使用内置函数和标准库
【10月更文挑战第18天】
25 3
|
3月前
|
存储 Go
|
3月前
|
JSON 监控 安全
go语言选择合适的工具和库
【10月更文挑战第17天】
25 2
|
3月前
|
存储 Go PHP
Go语言中的加解密利器:go-crypto库全解析
在软件开发中,数据安全和隐私保护至关重要。`go-crypto` 是一个专为 Golang 设计的加密解密工具库,支持 AES 和 RSA 等加密算法,帮助开发者轻松实现数据的加密和解密,保障数据传输和存储的安全性。本文将详细介绍 `go-crypto` 的安装、特性及应用实例。
179 0
|
4月前
|
Linux 编译器 Go
cgo--在Go中链接外部C库
cgo--在Go中链接外部C库
|
6月前
|
存储 JSON 前端开发
一文搞懂 Go 1.21 的日志标准库 - slog
一文搞懂 Go 1.21 的日志标准库 - slog
208 2
|
6月前
|
XML Go 数据库