与えられた
var dst, src map[K]V
src
からdst
にすべてのエントリをコピーできます
for k, v := range src {
dst[k] = v
}
これを行うためのより慣用的な方法はありますか?
copy
はスライスでのみ機能します(およびソースとしてstring
)。
これは私にこれを行うための完全に素晴らしい方法のように見えます。あるマップを別のマップにコピーすることは、ワンライナーソリューションを実現するほど一般的ではないと思います。
単純なfor range
ループを使用するのが最も効率的なソリューションです。
組み込みのcopy
は、src
のメモリをdst
のアドレスにコピーすることはできません。メモリレイアウトがまったく異なる可能性があるためです。マップは、そこに保存されているアイテムの数に対応するために成長します。たとえば、100万個の要素を持つマップがある場合、新しく作成した新しいマップよりも多くのメモリを占有するため、組み込みのcopy
は、新しいメモリを割り当てることなくメモリをコピーすることはできません。
マップが大きい場合、再ハッシュや再割り当てを避けるために十分な容量を持つデスティネーションマップを作成すると、要素のコピーを高速化できます(初期容量はサイズに制限されません):
dst := make(map[K]V, len(src))
for k, v := range src {
dst[k] = v
}
パフォーマンスが問題にならない場合(たとえば、小さなマップで作業している場合)、 reflect
パッケージを使用して一般的なソリューションを作成できます。
func MapCopy(dst, src interface{}) {
dv, sv := reflect.ValueOf(dst), reflect.ValueOf(src)
for _, k := range sv.MapKeys() {
dv.SetMapIndex(k, sv.MapIndex(k))
}
}
このソリューションは、引数が実際にマップされているかどうか、および宛先がnil
でないかどうかをチェックしません。それをテストする:
m1 := map[int]string{1: "one", 2: "two"}
m2 := map[int]string{}
MapCopy(m2, m1)
fmt.Println(m2)
m3 := map[string]int{"one": 1, "two": 2}
m4 := map[string]int{}
MapCopy(m4, m3)
fmt.Println(m4)
出力( Go Playground で試してください):
map[1:one 2:two]
map[one:1 two:2]
github.com/linkosmos/mapop を使用できます
input := map[string]interface{}{
"Key1": 2,
"key3": nil,
"val": 2,
"val2": "str",
"val3": 4,
}
input2 := map[string]interface{}{
"a2": "str",
"a3": 4,
}
input = mapop.Merge(input, input2)
input{"Key1": 2, "key3": nil, "val": 2, "val2": "str", "val3": 4, "a2": "str", "a3": 4}