深入探索Go?1.21中的?maps工具庫
前言
隨著 Go 1.21.0 版本的發(fā)布,新增了兩個實用的泛型工具庫:maps 和 slices,它們分別提供了處理映射(map)和切片常見操作的函數(shù),減少了我們重復(fù)造輪子的過程,提高開發(fā)效率。本文將會對 maps 工具庫進行介紹。
準備好了嗎?準備一杯你最喜歡的咖啡或茶,隨著本文一探究竟吧。
Maps
maps 是一個泛型工具庫,該庫包含了對任何類型都支持的實用函數(shù),函數(shù)簡介如下表所示:
| 函數(shù) | 函數(shù)簽名 | 功能 |
|---|---|---|
| Clone | func Clone[M ~map[K]V, K comparable, V any](m M) M | 該函數(shù)返回 m 的一個副本,底層基于淺層克隆去實現(xiàn),使用普通賦值的方式去設(shè)置新的鍵值對 |
| Copy | func Copy[M1 ~map[K]V, M2 ~map[K]V, K comparable, V any](dst M1, src M2) | 復(fù)制 src 中的所有鍵值對到 dst 中,如果 dst 中包含 src 中的任意 key,則該 key 對應(yīng)的 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 是否包含相同的鍵值對,內(nèi)部使用 == 進行比較 |
| 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 函數(shù),但通過 eq 函數(shù)進行比較值,鍵仍使用 == 進行比較 |
Clone
Clone 函數(shù)接收一個 m 參數(shù),該函數(shù)的功能是返回 m 的副本,底層基于淺層克隆去實現(xiàn),使用普通賦值的方式去設(shè)置新的鍵值對。
代碼示例:
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)
}執(zhí)行結(jié)果:
m1: map[programmer-01:{陳明勇 深圳} programmer-02:{張三 廣州}]
m2: map[programmer-01:{陳明勇 深圳} programmer-02:{張三 廣州}]
上述例子中,首先創(chuàng)建一個 map 類型的變量 m1,然后通過 maps.Clone() 函數(shù)進行克隆,得到 m2,最后通過打印結(jié)果可知 m2 的值和 m1 的值一樣。
從函數(shù)的功能描述中可知,Clone 函數(shù)的原理是淺層克隆,那么修改克隆后的 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"])
}執(zhí)行結(jié)果
m1: {陳明勇 深圳}, {張三 廣州}
m2: {陳明勇 深圳}, {張三 廣州}
m2 被修改后,m1: {陳明勇 深圳}, {張三 ??趠
m2 被修改后,m2: {陳明勇 深圳}, {張三 ??趠
與前面的示例不同,這個例子中的一個關(guān)鍵區(qū)別在于 value 是指針類型。從執(zhí)行結(jié)果可以明顯看出,如果 m1 的 value 是指針類型,那么在對克隆后的 m2 中的任意 key 對應(yīng)的 value 進行修改操作后,都會直接影響到 m1。這是因為 m1 和 m2 共享了同一組指向相同 Programmer 結(jié)構(gòu)體的指針,因此對一個指針的修改會在兩個 map 中都可見。
Copy
Copy 函數(shù)接收兩個 map 參數(shù) dst 和 src,該函數(shù)的功能是復(fù)制 src 中的所有鍵值對到 dst 中,如果 dst 中包含 src 中的任意 key,則該 key 對應(yīng)的 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)
}執(zhí)行結(jié)果:
map[City:廣州 Name:陳明勇 Phone:123456789]
在上述例子中,首先創(chuàng)建了兩個 map 變量,分別為 m1 和 m2,然后通過 maps.Copy 函數(shù),將 m2 中的鍵值對復(fù)制到 m1 中,最后打印復(fù)制后的結(jié)果。
根據(jù)結(jié)果可知,由于 m1 和 m2 都包含 key → City,因此在執(zhí)行復(fù)制操作后, m1 中的 key → City 對應(yīng)的 value 值會被覆蓋。
DeleteFunc
DeleteFunc 函數(shù)接收一個 map 類型的參數(shù) m 和一個函數(shù)類型的參數(shù) del。該函數(shù)的功能是刪除 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)
}執(zhí)行結(jié)果:
map[1:陳明勇 3:李四]
在上述例子中,首先創(chuàng)建了一個 map 變量 m1,使用 int 類型作為學(xué)號(key),string 類型作為姓名(value),然后通過 maps.DeleteFunc 刪除學(xué)號為雙數(shù)的學(xué)生,匿名函數(shù)的邏輯是 當學(xué)號為雙數(shù)時,返回 true。
總體來說這個例子相對簡單,讀者可根據(jù)實際應(yīng)用場景進行使用 DeleteFunc 函數(shù)。
Equal
Equal 函數(shù)接收兩個 map 變量,函數(shù)的返回值為 bool 類型。該函數(shù)的功能是判斷兩個 map 是否包含相同的鍵值對,內(nèi)部使用 == 進行比較。注意: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
}執(zhí)行結(jié)果:
false
true
上述例子中,首先創(chuàng)建了三個 map 類型變量,分別是 m1、m2 和 m3,然后通過 maps.Equal() 函數(shù),對 m1 和 m2 以及 m1 和 m3 進行等價比較。執(zhí)行結(jié)果與預(yù)期一致,m1 和 m3 是相等的,m1 和 m2 不相等。
EqualFunc
EqualFunc 函數(shù)類似 Equal 函數(shù),只不過是通過 eq 函數(shù)進行比較值,鍵仍使用 == 進行比較。注意: 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技術(shù)干貨", 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
}執(zhí)行結(jié)果:
false
true
上述例子中,首先創(chuàng)建了三個 map 類型變量,分別是 m1、m2 和 m3。這些 map 使用 int 類型作為編號(key),User 類型作為用戶信息(value)。
接著,使用 maps.EqualFunc() 函數(shù),對 m1 和 m2 以及 m1 和 m3 進行等價比較,在這個函數(shù)中,我們自定義了比較函數(shù) eq,其邏輯是只要兩個 User 結(jié)構(gòu)體的 IdCard 相同,就認為它們是同一個人(相等)。執(zhí)行結(jié)果與預(yù)期一致,m1 和 m3 是相等的,m1 和 m2 不相等。
小結(jié)
本文對 Go 工具庫 maps 進行詳細介紹,包括其提供的函數(shù) Clone、Copy、DeleteFunc、Equal 和 EqualFunc,并強調(diào)了使用這些函數(shù)時需要注意的地方。
總的來說,通過使用這些函數(shù),減少了我們重復(fù)造輪子的過程,提高開發(fā)效率。
你使用 maps 工具庫了嗎?
推薦閱讀
Go 1.21新內(nèi)置函數(shù)min、max和clear的用法詳解
到此這篇關(guān)于深入探索Go 1.21中的 maps工具庫的文章就介紹到這了,更多相關(guān)Go 1.21 maps內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
golang封裝一個執(zhí)行命令行的函數(shù)(return?stderr/stdout/exitcode)示例代碼
在?Go?語言中,您可以使用?os/exec?包來執(zhí)行外部命令,不通過調(diào)用?shell,并且能夠獲得進程的退出碼、標準輸出和標準錯誤輸出,下面給大家分享golang封裝一個執(zhí)行命令行的函數(shù)(return?stderr/stdout/exitcode)的方法,感興趣的朋友跟隨小編一起看看吧2024-06-06
Go 語言json.Unmarshal 遇到的小問題(推薦)
這篇文章主要介紹了 Go 語言json.Unmarshal 遇到的小問題,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-07-07

