Копирование всех элементов карты в другую

Учитывая

var dst, src map[K]V

Я могу скопировать все записи из src в dst, выполнив

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

Есть ли более идиоматический способ сделать это?

copy работает только на срезах (и string в качестве источника).

Ответ 1

Это выглядит как прекрасный способ сделать это со мной. Я не думаю, что копирование одной карты в другую достаточно распространено, чтобы иметь однострочное решение.

Ответ 2

Использование простого цикла 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]

Ответ 3

Вы можете использовать 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}