Golang中如何一行代码实现map的拷贝
Golang中如何一行代码实现map的拷贝 我有一个非常大的映射。我不想通过迭代来将其复制到另一个映射中。有没有其他解决方案?
我能想到的一个方法是将映射数据存入数据库,然后再重新读取,但这会增加一次额外的查询操作,代价较高。
那么可行的解决方案应该是什么呢?
我想进行拷贝,因为映射是按引用传递的,而我不想传递那个映射。
一个 Stack Overflow 回答建议在循环中复制映射:https://stackoverflow.com/a/23058707/9455968
使用 for 循环并复制数据可能是最快且最容易理解的解决方案。如果您坚持尝试其他方法,可以尝试转换为 JSON 再转换回来,但我不建议这样做。
是的,我尝试使用了gob,但我必须注册所有类型,这很繁琐,而且我不知道我的映射(来自前端的过滤器)可能有多复杂。那么,我是否应该找到所有类型并在gob中注册呢?
如果它这么大,为什么不找其他解决方案而不用复制呢?我的意思是,复制是绝对必要的吗?否则,正如上面所说,由于这是引用类型,除了在循环中复制每个元素之外别无他法。
我遇到了这个问题。
https://play.golang.org/p/MRpurSATQuV
可以看到只进行了一层复制。在内部我们可以替换内容,但它仍然会引用原始映射。
func main() {
fmt.Println("hello world")
}
不理解您的使用场景。但如果您要复制它,为什么不从一开始就维护重复的映射,就像这样:
package main
import "fmt"
func main() {
m1 := map[string]int{"a": 1, "b": 2}
m2 := map[string]int{}
for k, v := range m1 {
m2[k] = v
}
fmt.Println(m2)
}
最快的序列化方法是使用 “encoding/gob” 对映射进行编码/解码。
为什么不创建一个包含此映射的结构体接收器(不导出该映射)并在其上实现查找或获取方法(只读)?类似这样:
type MyMap struct {
myHugeMap map[string]string
}
func (m *MyMap) get(i string) (string, error) {
e, ok := m.myHugeMap[i]
if !ok {
return "", fmt.Errorf("element %s not found", i)
}
return e, nil
}
当然,这应该放在单独的包中,并且需要传递该结构体的指针。
如果你有很多新类型的值,那么你需要注册它们,但如果只是少数新类型,考虑到 encoding/gob 相对于 encoding/json 的速度优势,这并不算太麻烦。
但如果你是从未知数据创建初始映射,那么我假设它是一个标准的 map[string]interface{} 值。如果是这样,就不需要类型注册。
这里:https://play.golang.org/p/it0mLk1vd8f。
注意:如果你是基于结构体定义进行 gob 编码/解码,则无需注册:https://play.golang.org/p/Pv0tPAcU74v。
感谢,JSON 序列化和反序列化功能正常。我还转向了一种更简单的迭代和复制方案,但还需要测试负载情况。
func copy(originalMap map[string]interface{}) map[string]interface{} {
newMap := make(map[string]interface{})
for key, value := range originalMap {
newMap[key] = value
}
return newMap
}
func appendWith(toAppend bson.M, filter map[string]interface{}) error {
value := filter["cond"]
marshallValue, err := json.Marshal(value)
if err != nil {
return errors.Wrap(err, "json marshall")
}
var unmarshallValue []interface{}
err = json.Unmarshal(marshallValue, &unmarshallValue)
if err != nil {
return errors.Wrap(err, "json unmarshall")
}
var res []interface{}
res = append(res, unmarshallValue...)
_ = append(res, toAppend)
return nil
}
老实说,如果没有更多背景信息,我不确定自己或其他人能给你更多帮助。我们都知道你想复制一个映射,担心内部代码会修改映射中的数据,而且你显然在使用 map[string]interface{}(这本身可能被视为代码异味),但这些信息并不能完整描绘你正在做什么以及为什么这么做,因此很难给出合理的建议。
这就好比你要我推荐适合你汽车的轮胎,而我却不知道你是住在常年下雪的地方、季节性下雪的地区还是永远阳光明媚的地方。又或者你打算把车开上赛道,需要完全不同的轮胎类型。关键是,我可以尝试给你一些模糊的通用建议,但最终这些都只是可能不太有用的泛泛之谈。
如果你坚持每次都要克隆映射,可以将其编码为 JSON 然后重新解码到新的映射变量中,这样每次都能实现深度克隆(据我所知),但速度会比较慢。可能比反复查询数据库快一些,但依然算不上高速。
如果你想获得更好的建议,我认为我们需要更深入了解你的具体场景,这样才能帮你找到可行的解决方案——无论这个方案是否包含克隆 map[string]interface{}。
在Go语言中,可以使用一行代码实现map的拷贝,无需显式迭代。具体方法是利用Go语言内置的maps包(从Go 1.21版本开始提供)的Clone函数。这个函数会创建一个新的map,并复制原始map中的所有键值对。
示例代码:
package main
import (
"fmt"
"maps"
)
func main() {
originalMap := map[string]int{"a": 1, "b": 2, "c": 3}
copiedMap := maps.Clone(originalMap) // 一行代码实现map拷贝
fmt.Println("Original:", originalMap)
fmt.Println("Copied:", copiedMap)
}
输出:
Original: map[a:1 b:2 c:3]
Copied: map[a:1 b:2 c:3]
如果使用的是Go 1.21之前的版本,可以自定义一个函数来实现类似功能,但需要多行代码。例如:
func copyMap[K comparable, V any](m map[K]V) map[K]V {
result := make(map[K]V, len(m))
for k, v := range m {
result[k] = v
}
return result
}
使用示例:
copiedMap := copyMap(originalMap)
这种方法避免了数据库操作的开销,直接在内存在完成拷贝,效率更高。

