如何复制地图?

The*_*hat 54 go

我正在尝试将map(amap)的内容复制到另一个()内部aSuperMap然后清除, amap以便它可以在下一个迭代/循环中获取新值.问题是,如果不在超图中清除其引用,则无法清除地图.这是一些伪代码.

for something := range fruits{
        aMap := make(map[string]aStruct)
        aSuperMap := make(map[string]map[string]aStruct)

        for x := range something{
            aMap[x] = aData
            aSuperMap[y] = aMap
            delete(aMap, x)
    }
//save aSuperMap
  saveASuperMap(something)

}
Run Code Online (Sandbox Code Playgroud)

我也试过一些动态的东西,但很明显它会抛出一个错误(不能分配给nil)

aSuperMap[y][x] = aData
Run Code Online (Sandbox Code Playgroud)

问题是如何创建关联映射?在PHP中,我只使用aSuperMap [y] [x] = aData.似乎golang没有任何明显的方法.如果我delete(aMap, x)从超级地图中删除 它的引用也会被删除.如果我不删除它,supermap最终会出现重复数据.基本上在每个循环中它aMap使用新值加上所有旧值.

Chr*_*ian 94

您没有复制地图,而是复制地图.delete因此,您可以修改原始地图和超级地图中的值.要复制地图,您必须使用如下for循环:

for k,v := range originalMap {
  newMap[k] = v
}
Run Code Online (Sandbox Code Playgroud)

以下是现已退役的SO文档中的示例:

// Create the original map
originalMap := make(map[string]int)
originalMap["one"] = 1
originalMap["two"] = 2

// Create the target map
targetMap := make(map[string]int)

// Copy from the original map to the target map
for key, value := range originalMap {
  targetMap[key] = value
}
Run Code Online (Sandbox Code Playgroud)

摘自地图 - 复制地图.原作者是JepZ.归因详细信息可在贡献者页面上找到.源是根据CC BY-SA 3.0许可的,可以在文档存档中找到.参考主题ID:732和示例ID:9834.

  • 另见[http://golang.org/doc/effective_go.html#maps](http://golang.org/doc/effective_go.html#maps).重要的部分实际上是"对底层数据结构的引用".这也适用于切片. (4认同)
  • 您可能希望使用“targetMap := make(map[string]int, len(originalMap))”来促进预分配映射 (4认同)

Fra*_*ula 12

我会使用递归,以防万一,以便您可以深度复制,map并避免出现错误的情况,以防您要更改本身就是一个map元素map

这是utils.go中的示例

package utils

func CopyMap(m map[string]interface{}) map[string]interface{} {
    cp := make(map[string]interface{})
    for k, v := range m {
        vm, ok := v.(map[string]interface{})
        if ok {
            cp[k] = CopyMap(vm)
        } else {
            cp[k] = v
        }
    }

    return cp
}
Run Code Online (Sandbox Code Playgroud)

及其测试文件(即utils_test.go):

package utils

import (
    "testing"

    "github.com/stretchr/testify/require"
)

func TestCopyMap(t *testing.T) {
    m1 := map[string]interface{}{
        "a": "bbb",
        "b": map[string]interface{}{
            "c": 123,
        },
    }

    m2 := CopyMap(m1)

    m1["a"] = "zzz"
    delete(m1, "b")

    require.Equal(t, map[string]interface{}{"a": "zzz"}, m1)
    require.Equal(t, map[string]interface{}{
        "a": "bbb",
        "b": map[string]interface{}{
            "c": 123,
        },
    }, m2)
}
Run Code Online (Sandbox Code Playgroud)

如果您需要将map密钥设置为其他值而不是,它应该很容易重新适配string

  • 这是否还应该包括切片检测,因为切片可以具有相同的效果? (8认同)
  • 多久有人发布带有测试文件的解决方案!谢谢你。来这里进行深拷贝。 (3认同)

小智 6

您可以通过以下方式往返encoding/gob

package main

import (
   "bytes"
   "encoding/gob"
)

func copyMap(in, out interface{}) {
   buf := new(bytes.Buffer)
   gob.NewEncoder(buf).Encode(in)
   gob.NewDecoder(buf).Decode(out)
}

func main() {
   a := map[string]int{"month": 12, "day": 31}
   b := make(map[string]int)
   copyMap(a, &b)
}
Run Code Online (Sandbox Code Playgroud)

这也适用于其他软件包。这是一个示例net/url

package main

import (
   "fmt"
   "net/url"
)

func copyVal(v url.Values) url.Values {
   u := url.URL{
      RawQuery: v.Encode(),
   }
   return u.Query()
}

func main() {
   a := url.Values{
      "west": {"left"}, "east": {"right"},
   }
   b := copyVal(a)
   fmt.Println(b)
}
Run Code Online (Sandbox Code Playgroud)


Nat*_* F. 5

正如seong 的评论中所述:

另请参阅http://golang.org/doc/ effective_go.html #maps 。重要的部分实际上是“对底层数据结构的引用”。这也适用于切片。

然而,这里的解决方案似乎都没有为也覆盖切片的正确深度复制提供解决方案。

我稍微改变了弗朗西斯科·卡苏拉的答案,以适应地图和切片。


这应该涵盖复制地图本身以及复制任何子地图或切片。两者都受到相同的“底层数据结构”问题的影响。它还包括一个实用函数,用于直接在切片上执行相同类型的深度复制。

请记住,结果映射中的切片的类型为[]interface{},因此在使用它们时,您需要使用类型断言来检索预期类型的​​值。

用法示例

地图(也会自动深复制切片)

copy := CopyableMap(originalMap).DeepCopy()
Run Code Online (Sandbox Code Playgroud)

切片(也会自动深复制地图)

copy := CopyableSlice(originalSlice).DeepCopy()
Run Code Online (Sandbox Code Playgroud)

来源

deepcopy.go

package utils

type CopyableMap   map[string]interface{}
type CopyableSlice []interface{}

// DeepCopy will create a deep copy of this map. The depth of this
// copy is all inclusive. Both maps and slices will be considered when
// making the copy.
func (m CopyableMap) DeepCopy() map[string]interface{} {
    result := map[string]interface{}{}

    for k,v := range m {
        // Handle maps
        mapvalue,isMap := v.(map[string]interface{})
        if isMap {
            result[k] = CopyableMap(mapvalue).DeepCopy()
            continue
        }

        // Handle slices
        slicevalue,isSlice := v.([]interface{})
        if isSlice {
            result[k] = CopyableSlice(slicevalue).DeepCopy()
            continue
        }

        result[k] = v
    }

    return result
}

// DeepCopy will create a deep copy of this slice. The depth of this
// copy is all inclusive. Both maps and slices will be considered when
// making the copy.
func (s CopyableSlice) DeepCopy() []interface{} {
    result := []interface{}{}

    for _,v := range s {
        // Handle maps
        mapvalue,isMap := v.(map[string]interface{})
        if isMap {
            result = append(result, CopyableMap(mapvalue).DeepCopy())
            continue
        }

        // Handle slices
        slicevalue,isSlice := v.([]interface{})
        if isSlice {
            result = append(result, CopyableSlice(slicevalue).DeepCopy())
            continue
        }

        result = append(result, v)
    }

    return result
}
Run Code Online (Sandbox Code Playgroud)

测试文件 ( deepcopy_tests.go)

package utils

import (
    "testing"

    "github.com/stretchr/testify/require"
)

func TestCopyMap(t *testing.T) {
    m1 := map[string]interface{}{
        "a": "bbb",
        "b": map[string]interface{}{
            "c": 123,
        },
        "c": []interface{} {
            "d", "e", map[string]interface{} {
                "f": "g",
            },
        },
    }

    m2 := CopyableMap(m1).DeepCopy()

    m1["a"] = "zzz"
    delete(m1, "b")
    m1["c"].([]interface{})[1] = "x"
    m1["c"].([]interface{})[2].(map[string]interface{})["f"] = "h"

    require.Equal(t, map[string]interface{}{
        "a": "zzz", 
        "c": []interface{} {
            "d", "x", map[string]interface{} {
                "f": "h",
            },
        },
    }, m1)
    require.Equal(t, map[string]interface{}{
        "a": "bbb",
        "b": map[string]interface{}{
            "c": 123,
        },
        "c": []interface{} {
            "d", "e", map[string]interface{} {
                "f": "g",
            },
        },
    }, m2)
}
Run Code Online (Sandbox Code Playgroud)