2011-09-15 38 views
59

鑑於複製地圖中的所有元素到另一個

var dst, src map[K]V 

我可以通過做

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

複製從src所有條目到dst有沒有一種更地道的方式來做到這一點?

copy只適用於切片(和string作爲來源)。

回答

44

這看起來像一個完美的方式來做到這一點對我來說。我不認爲將一張地圖複製到另一張地圖是很普遍的,因此可以採用單線解決方案。

+24

這是一個恥辱'copy'僅適用於片。 –

+16

「我不認爲將地圖複製到另一個地圖足夠普遍」......這是我的主要寵兒。對於所有其他語言的本機類型,這是非常容易的。 –

+7

@EduFelipe我同意。 Go的內置通用類型(例如地圖)的特殊性,以及缺少以任何方式在用戶定義的類型中獲得相同類型的功能(例如不支持泛型),這是Go最大的問題之一。這只是我愛Rust的許多原因之一。 –

7

使用簡單的for range循環是最有效的解決方案。

請注意,內置copy不能將src的內存複製到dst的地址,因爲它們可能具有完全不同的內存佈局。地圖增長以適應存儲在其中的項目數量。例如,如果你有一百萬個元素的地圖,它會佔用比新創建的新地圖更多的內存,所以內建的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] 
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} 
相關問題