2011-09-15 8 views
59

にマップのすべての要素をコピーする考えると別の

var dst, src map[K]V 

私はこれを行うにはより多くの慣用的な方法はあり

for k, v := range src { 
    dst[k] = v 
} 

を行うことによってdstsrcからすべてのエントリをコピーすることができますか?

copyは、スライス(およびソースとしてstring)でのみ機能します。

答えて

44

これは私にとってこれを行うための完璧な方法です。 1つのマップを別のマップにコピーすることは、1ライナーの解決策を取るには十分だとは思いません。

+24

使用することができます 'copy'はスライスのみで動作します。 –

+16

「地図を別の地図にコピーするのは十分だとは思わない」...それは私の主なペットの仲間です。それはそこの他の言語のネイティブタイプでは本当に簡単なことです。 –

+7

@EduFelipe私は同意します。 Goのビルトインジェネリックタイプ(マップなど)の特質や、ユーザー定義タイプ(たとえばジェネリックスのサポートなし)で同じ種類の機能を使用する方法がないことは、Goの最大の課題の1つです。そしてそれは私がRustを愛する多くの理由の一つに過ぎません。 –

7

単純なfor rangeループを使用するのが最も効率的なソリューションです。

copyは、メモリが完全に異なる場合があるので、dstのアドレスにsrcのメモリをコピーできないことに注意してください。マップは、そこに格納されているアイテムの数に対応するように拡張されます。たとえば、百万の要素を持つマップを作成した場合、新しく作成されたマップよりもはるかに多くのメモリを占有するため、copyの組み込み関数では、新しいメモリを割り当てずにメモリをコピーできませんでした。

マップが大きい場合、あなたは焼き直しと再割り当てを回避するためにビッグ十分な容量を持つ先のマップを作成する可能性がある場合要素をコピースピードアップすることができますが、例えば(初期容量は、そのサイズを拘束されません)パフォーマンスが問題(例えば、あなたが小さなマップで作業している)でない場合は、一般的な解決策はreflectパッケージを使用して作成することができる

dst := make(map[K]V, len(src)) 

for k, v := range src { 
    dst[k] = v 
} 

:引数が本当にマップである場合

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] 
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}