2011-09-15 25 views

Respuesta

44

Parece una forma perfecta de hacer esto para mí. No creo que copiar un mapa en otro sea lo suficientemente común como para tener una solución de una sola línea.

+24

Es una pena 'copy' sólo funciona en rodajas. –

+16

"No creo que copiar un mapa en otro sea lo suficientemente común" ... esa es mi principal preocupación con Go. Eso es algo realmente fácil de hacer en tipos nativos en cualquier otro idioma que exista. –

+7

@EduFelipe Estoy de acuerdo. La naturaleza especial de los tipos genéricos incorporados de Go (por ejemplo, mapas) y la falta de cualquier forma de obtener el mismo tipo de funcionalidad en los tipos definidos por el usuario (por ejemplo, sin compatibilidad con los genéricos), es uno de mis mayores problemas con Go. Y es solo una de las muchas razones por las que amo a Rust. –

7

El uso de un lazo simple for range es la solución más eficiente.

Tenga en cuenta que un built-in copy no puede simplemente copiar la memoria de src a la dirección de dst porque pueden tener un diseño de memoria completamente diferente. Los mapas crecen para acomodar la cantidad de elementos almacenados en ellos. Entonces, por ejemplo, si tiene un mapa con un millón de elementos, ocupa mucha más memoria que un mapa nuevo recién creado, por lo que un copy integrado no podría simplemente copiar memoria sin asignar nueva.

Si el mapa es grande, se puede acelerar la copia de los elementos si es posible crear el mapa de destino que tenga una capacidad-lo suficientemente grande para evitar refrito y reasignación (la capacidad inicial no ligado su tamaño), por ejemplo:

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

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

Si el rendimiento no es un problema (por ejemplo, se trabaja con pequeños mapas), una solución general puede ser creado usando el paquete de 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)) 
    } 
} 

Esta solución no comprueba si los argumentos son realmente mapas y si el destino no es nil. Prueba de ello:

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) 

salida (probarlo en el Go Playground):

map[1:one 2:two] 
map[one:1 two:2] 
2

Usted podría utilizar 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} 
Cuestiones relacionadas