我尝试将地图内容(amap
)复制到另一个(aSuperMap
)中,然后清除amap
以便它可以在下一次迭代/循环。
问题是您无法清除超图中的地图without to clear its reference。
这是一些伪代码。
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)
}
我也试过一些动态的东西,但显然它会抛出一个错误(不能指定为零)
aSuperMap[y][x] = aData
问题是如何创建关联地图?在PHP中,我只使用aSuperMap [y] [x] = aData。似乎golang没有任何明显的方法。如果我删除delete(aMap, x)
,也会删除超级地图中的引用。如果我不删除它,则supermap最终会出现重复数据。基本上在每个循环上,它使用新值加上所有旧值获得aMap
。
答案 0 :(得分:82)
您没有复制地图,而是复制地图。您的delete
因此会修改原始地图和超级地图中的值。要复制地图,您必须使用for
这样的循环:
for k,v := range originalMap {
newMap[k] = v
}
以下是现已退役的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
}
摘自Maps - Copy a Map。原作者是JepZ。归因详情可在contributor page上找到。该来源在CC BY-SA 3.0下获得许可,可以在Documentation archive中找到。参考主题ID:732和示例ID:9834。
答案 1 :(得分:5)
我将使用递归,以防万一,以便您可以深度复制map
并避免发生错误的情况,以防万一要更改本身为map
的{{1}}元素。 / p>
以下是 utils.go 中的示例:
map
及其测试文件(即 utils_test.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
}
如果您需要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)
}
键而不是map
来代替其他键,那么重新安装应该足够容易。
答案 2 :(得分:1)
单个元素副本,它似乎只是一个简单的例子。
maps := map[string]int {
"alice":12,
"jimmy":15,
}
maps2 := make(map[string]int)
for k2,v2 := range maps {
maps2[k2] = v2
}
maps2["miki"]=rand.Intn(100)
fmt.Println("maps: ",maps," vs. ","maps2: ",maps2)
答案 3 :(得分:1)
您必须手动将每个键/值对复制到新的map
。这是一个循环,人们在需要map
的深拷贝时必须重新编程。
您可以通过使用{p> 3来安装maps
软件包中的mapper
来自动生成此功能。
go get -u github.com/drgrib/maps/cmd/mapper
并运行
mapper -types string:aStruct
将会生成文件map_float_astruct.go
,该文件不仅包含地图的(深)Copy
,还包含其他“缺失”的map
函数ContainsKey
,{{1} },ContainsValue
和GetKeys
:
GetValues
完全公开:我是该工具的创建者。我创建了它及其包含的包,因为我发现自己不断地为Go func ContainsKeyStringAStruct(m map[string]aStruct, k string) bool {
_, ok := m[k]
return ok
}
func ContainsValueStringAStruct(m map[string]aStruct, v aStruct) bool {
for _, mValue := range m {
if mValue == v {
return true
}
}
return false
}
func GetKeysStringAStruct(m map[string]aStruct) []string {
keys := []string{}
for k, _ := range m {
keys = append(keys, k)
}
return keys
}
func GetValuesStringAStruct(m map[string]aStruct) []aStruct {
values := []aStruct{}
for _, v := range m {
values = append(values, v)
}
return values
}
func CopyStringAStruct(m map[string]aStruct) map[string]aStruct {
copyMap := map[string]aStruct{}
for k, v := range m {
copyMap[k] = v
}
return copyMap
}
重写这些算法以适应不同的类型组合。
答案 4 :(得分:1)
如seong's comment中所述:
另请参见http://golang.org/doc/effective_go.html#maps。重要的部分实际上是“对基础数据结构的引用”。这也适用于切片。
但是,这里的解决方案似乎都无法为适当的深层复制(也包括切片)提供解决方案。
我对Francesco Casula's answer做了一些改动,以适应地图和切片。
这应该包括复制地图本身以及复制任何子地图或切片。两者都受到相同的“基础数据结构”问题的影响。它还包括一个实用程序功能,可直接在片上执行相同类型的Deep Copy。
请记住,结果映射中的切片将为[]interface{}
类型,因此在使用它们时,您将需要使用type assertion来检索期望类型的值。
用法示例
copy := CopyableMap(originalMap).DeepCopy()
源文件(util.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
}
测试文件(util_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)
}
答案 5 :(得分:0)
您可以通过 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)
}
这也适用于其他软件包。下面是一个带有 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)
}