Go1.21で追加された「mapsパッケージ」とは?実際にパッケージ内の関数を使うコードを書いてみた。
気づいたらGo1.22がリリースされていましたが、今回は引き続き1.21で追加されたパッケージを調べようと思います。
今回はmapsパッケージについて解説します。
mapsパッケージの概要
Package maps defines various functions useful with maps of any type.
https://pkg.go.dev/golang.org/x/exp/maps
と今回もドキュメントの概要にあるように、mapsパッケージは、あらゆる型のマップに対して役立つ関数を提供しているパッケージのようです。
mapsパッケージの関数
Clone | 引数のマップのコピーを返します。 |
---|---|
Copy | 第二引数のマップのすべてのkey/valueのペアを第一引数にコピーします。 |
DeleteFunc | 引数に渡した関数がtrueを返したkey/valueのペアを削除します。 |
Equal | 二つのマップが同じkey/valueを持っているかを判定します。 |
EqualFunc | 渡した関数によってvalueを比較する方法で、二つのマップが同じkey/valueを持っているかを判定します。 |
mapsパッケージの関数の使用例
それではこれらの関数を使って実際にコードを書いてみます。
Clone
m1 := map[string]string{
"a": "a",
}
m2 := maps.Clone(m1)
fmt.Println(m1["a"]) // a
fmt.Println(m2["a"]) // a
m2["a"] = "b"
fmt.Println(m1["a"]) // a
fmt.Println(m2["a"]) // b
このようにマップのコピーが作られます。このコピーは
This is a shallow clone
とあるようにディープコピーではないので、コピー先の変更がコピー元に影響する場合があるようです。
以下のコードが影響が出る場合を調べたものです。
m1 := map[string][]string{
"a": {"a"},
}
m2 := maps.Clone(m1)
// m1["a"]とm2["a"]の参照先のアドレスが同じ
fmt.Printf("m1[\"a\"] value = %v\n", m1["a"]) // m1["a"] value = [a]
fmt.Printf("m1[\"a\"] pointer = %p\n", m1["a"]) // m1["a"] pointer = 0xc0000a6020
fmt.Printf("m2[\"a\"] value = %v\n", m2["a"]) // m2["a"] value = [a]
fmt.Printf("m2[\"a\"] pointer = %p\n", m2["a"]) // m2["a"] pointer = 0xc0000a6020
// コピー先を変更してもコピー元に影響が出ない場合
m2["a"] = []string{"b"}
// m2["a"]が参照するアドレス自体が変更されるのでコピー元に影響が出ない
fmt.Printf("m1[\"a\"] value = %v\n", m1["a"]) // m1["a"] value = [a]
fmt.Printf("m1[\"a\"] pointer = %p\n", m1["a"]) // m1["a"] pointer = 0xc0000a6020
fmt.Printf("m2[\"a\"] value = %v\n", m2["a"]) // m2["a"] value = [b]
fmt.Printf("m2[\"a\"] pointer = %p\n", m2["a"]) // m2["a"] pointer = 0xc0000a6050
// コピー元に影響が出る場合
m3 := maps.Clone(m1)
m3["a"][0] = "b"
// m1["a"]とm3["a"]が参照するアドレスに保存されている値を変更したので、コピー元にも影響が出る
fmt.Printf("m1[\"a\"] value = %v\n", m1["a"]) // m1["a"] value = [b]
fmt.Printf("m1[\"a\"] pointer = %p\n", m1["a"]) // m1["a"] pointer = 0xc0000a6020
fmt.Printf("m3[\"a\"] value = %v\n", m3["a"]) // m3["a"] value = [b]
fmt.Printf("m3[\"a\"] pointer = %p\n", m3["a"]) // m3["a"] pointer = 0xc0000a6020
Copy
引数にマップを二つ渡し、第二引数のkey/valueペアを第一引数にコピーします。
もしコピー先にコピー元が持っているkeyが存在する場合は上書きされます。
m1 := map[string][]string{
"a": {"b"},
"c": {"d"},
}
m2 := map[string][]string{
"c": {"e", "f", "g"},,
}
// m2["c"]が上書きされる
maps.Copy(m2, m1)
fmt.Println(m1) // map[a:[b] c:[d]]
fmt.Println(m2) // map[a:[b] c:[d]]
// CopyもCloneと同じくshallowなコピーなもよう
m2["a"][0] = "x"
fmt.Println(m1) // map[a:[x] c:[d]]
fmt.Println(m2) // map[a:[x] c:[d]]
m2["a"] = []string{"y"}
fmt.Println(m1) // map[a:[x] c:[d]]
fmt.Println(m2) // map[a:[y] c:[d]]
DeleteFunc
m := map[string]int{
"alfa": 50,
"bravo": 51,
"charie": 99,
"delta": 12,
"echo": 3,
}
maps.DeleteFunc(m, func(k string, v int) bool {
return v > 50
})
fmt.Println(m) // map[alfa:50 delta:12 echo:3]
maps.DeleteFunc(m, func(k string, v int) bool {
return len(k) > 4
})
fmt.Println(m) // map[alfa:50 echo:3]
削除の条件を判定をするのに、key/valueどちらも利用できます。
Equal
m1 := map[string]string{
"dog": "Bowwow",
"cat": "Meow",
}
m2 := map[string]string{
"dog": "Bowwow",
"cat": "Meow",
}
m3 := map[string]string{
"dog": "bowwow",
"cat": "meow",
}
fmt.Println(maps.Equal(m1, m2)) // true
fmt.Println(maps.Equal(m1, m3)) // false
// comparableを実装していないスライス等には利用できない
//m4 := map[string][]int{
// "hoge": {1, 2, 3},
// "fuga": {2, 4, 6},
//}
//m5 := map[string][]int{
// "hoge": {1, 2, 3},
// "fuga": {2, 4, 6},
//}
// fmt.Println(maps.Equal(m4, m5))
EqualFunc
m1 := map[string]string{
"name": "John Doe",
"blood type": "A",
}
m2 := map[string]string{
"name": " john doe ",
"blood type": "a",
}
var eqFunc = func(v1 string, v2 string) bool {
return strings.TrimSpace(strings.ToUpper(v1)) == strings.TrimSpace(strings.ToUpper(v2))
}
eq := maps.EqualFunc(m1, m2, eqFunc)
fmt.Println(eq) // true
// keyは==で比較される
m3 := map[string]string{
"Name": "John Doe",
" blood type ": "A",
}
eq = maps.EqualFunc(m1, m3, eqFunc)
fmt.Println(eq) // false
コメントで書いたように、keyに関してはEqualFunc
に渡した関数ではなく==
で比較されます。
さいごに
mapsパッケージを利用することで今までのようにforループを回してkey/valueを新しいマップにコピーする、といったコードを書かずにスマートにコピーできるようになりました。マップを効率的に操作したい場合は、このパッケージを活用してみてください。
この記事を書いた人
-
これまで農業、士業と経験し、まったく異業種のエンジニアとしてアーティスに入社。
現在は事業開発部でバックエンドエンジニアとして仕事に従事。可読性の高いコードが書けるよう日々勉強中。趣味は一人旅。
関連記事
最新記事
FOLLOW US
最新の情報をお届けします
- facebookでフォロー
- Twitterでフォロー
- Feedlyでフォロー