Копирование всех элементов карты в другую - PullRequest
61 голосов
/ 16 сентября 2011

С учетом

var dst, src map[K]V

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

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

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

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

Ответы [ 3 ]

45 голосов
/ 16 сентября 2011

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

7 голосов
/ 04 августа 2015

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

Вы можете использовать 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}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...