Golang中如何复制包含指针的map

Golang中如何复制包含指针的map 我有一个包含指针的映射,想要复制/克隆它,然后修改复制后映射中的一些参数(同时不改变原始映射)。这里有一个简短的可运行示例: https://play.golang.org/p/LxPGXpedqei

问题在于,由于指针的存在,当我修改复制映射中的参数时,原始映射中的值也会随之改变。那么,如何正确地复制一个包含指针的映射呢?谢谢

2 回复

你的循环如下:

	for key, value := range originalMap { //! 必须通过 key,value 这种方式进行,否则会关联到同一个 map
		targetMap[key] = new(str)
		targetMap[key] = value
	}

你循环中的这部分代码创建了一个新的空 *str 结构体,但随后你又通过将原始的 value 指针复制到 targetMap 中覆盖了它。

我认为你想要做的应该是更像这样:

	// ------ 从原始 map 复制到目标 map
	for key, value := range originalMap { //! 必须通过 key,value 这种方式进行,否则会关联到同一个 map
		newStr := new(str)	// 创建新的 str
		*newStr = *value	// 解引用 value 指针
					// 并将 str 的值
					// 复制到 newStr。
		targetMap[key] = newStr
	}

https://play.golang.org/p/EaqKrccPpy7

更多关于Golang中如何复制包含指针的map的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


要正确复制包含指针的映射,你需要对映射中的每个指针值进行深拷贝。以下是几种实现方式:

方法1:手动深拷贝每个指针

package main

import "fmt"

type Data struct {
    Value int
}

func copyMapWithPointers(original map[string]*Data) map[string]*Data {
    copy := make(map[string]*Data, len(original))
    for k, v := range original {
        // 创建新的指针,复制结构体内容
        copy[k] = &Data{Value: v.Value}
    }
    return copy
}

func main() {
    original := map[string]*Data{
        "a": {Value: 1},
        "b": {Value: 2},
    }
    
    copied := copyMapWithPointers(original)
    copied["a"].Value = 100
    
    fmt.Println("Original:", original["a"].Value) // 输出: 1
    fmt.Println("Copied:", copied["a"].Value)     // 输出: 100
}

方法2:使用反射进行通用深拷贝

package main

import (
    "fmt"
    "reflect"
)

type Data struct {
    Value int
}

func deepCopyMap(original interface{}) interface{} {
    origValue := reflect.ValueOf(original)
    
    if origValue.Kind() != reflect.Map {
        return original
    }
    
    copy := reflect.MakeMap(origValue.Type())
    
    for _, key := range origValue.MapKeys() {
        origElem := origValue.MapIndex(key)
        
        if origElem.Kind() == reflect.Ptr {
            // 获取指针指向的值
            elemValue := origElem.Elem()
            // 创建新指针并复制值
            newPtr := reflect.New(elemValue.Type())
            newPtr.Elem().Set(elemValue)
            copy.SetMapIndex(key, newPtr)
        } else {
            copy.SetMapIndex(key, origElem)
        }
    }
    
    return copy.Interface()
}

func main() {
    original := map[string]*Data{
        "x": {Value: 10},
        "y": {Value: 20},
    }
    
    copied := deepCopyMap(original).(map[string]*Data)
    copied["x"].Value = 999
    
    fmt.Println("Original:", original["x"].Value) // 输出: 10
    fmt.Println("Copied:", copied["x"].Value)     // 输出: 999
}

方法3:使用序列化/反序列化(JSON)

package main

import (
    "encoding/json"
    "fmt"
)

type Data struct {
    Value int
}

func copyMapViaJSON(original map[string]*Data) (map[string]*Data, error) {
    var copied map[string]*Data
    
    // 序列化为JSON
    data, err := json.Marshal(original)
    if err != nil {
        return nil, err
    }
    
    // 反序列化创建新副本
    err = json.Unmarshal(data, &copied)
    if err != nil {
        return nil, err
    }
    
    return copied, nil
}

func main() {
    original := map[string]*Data{
        "key1": {Value: 42},
        "key2": {Value: 84},
    }
    
    copied, err := copyMapViaJSON(original)
    if err != nil {
        panic(err)
    }
    
    copied["key1"].Value = 0
    
    fmt.Println("Original:", original["key1"].Value) // 输出: 42
    fmt.Println("Copied:", copied["key1"].Value)     // 输出: 0
}

方法4:为结构体实现Clone方法

package main

import "fmt"

type Data struct {
    Value int
    Nested *NestedData
}

type NestedData struct {
    Text string
}

func (d *Data) Clone() *Data {
    cloned := &Data{
        Value: d.Value,
    }
    
    if d.Nested != nil {
        cloned.Nested = &NestedData{
            Text: d.Nested.Text,
        }
    }
    
    return cloned
}

func copyMapWithClone(original map[string]*Data) map[string]*Data {
    copy := make(map[string]*Data, len(original))
    for k, v := range original {
        copy[k] = v.Clone()
    }
    return copy
}

func main() {
    original := map[string]*Data{
        "item": {
            Value: 5,
            Nested: &NestedData{Text: "hello"},
        },
    }
    
    copied := copyMapWithClone(original)
    copied["item"].Value = 50
    copied["item"].Nested.Text = "world"
    
    fmt.Println("Original value:", original["item"].Value)           // 输出: 5
    fmt.Println("Original text:", original["item"].Nested.Text)      // 输出: hello
    fmt.Println("Copied value:", copied["item"].Value)               // 输出: 50
    fmt.Println("Copied text:", copied["item"].Nested.Text)          // 输出: world
}

方法1最简单直接,适合结构明确的情况。方法2更通用但性能较低。方法3适合需要序列化的场景。方法4在结构体复杂时最清晰可控。

回到顶部