如何在Golang中复制结构?

时间:2018-08-01 14:22:57

标签: go

我想复制一个对象,以便我有两个具有两个不同内存地址的相同对象。我对此的第一次尝试失败了:

aa := a
assert.NotEqual(t, &a, &aa, "Copied items should not be the same object.") // Test fails

我可以解决这个问题,使其真正复制该结构吗?这种结构没有什么特别的。

4 个答案:

答案 0 :(得分:5)

在进行中,原始类型和仅包含原始类型的结构按值复制,因此您可以通过简单地分配给新变量(或从函数返回)来复制它们。例如:

type Person struct{
  Name string
  Age  int
}

alice1 := Person{"Alice", 30}
alice2 := alice1
fmt.Println(alice1 == alice2)   // => true, they have the same field values
fmt.Println(&alice1 == &alice2) // => false, they have different addresses

alice2.Age += 10
fmt.Println(alice1 == alice2)   // => false, now they have different field values

请注意,正如评论者所提到的,示例中的混乱很可能是由于所使用的测试库的语义所致。

如果您的结构碰巧包含数组,切片或指针,那么除非您希望在副本之间保留引用,否则您将需要对所引用对象执行深层复制。 Golang没有提供内置的深层复制功能,因此您必须实现自己的深层复制功能或使用提供它的许多免费可用库之一。

答案 1 :(得分:1)

DeepCopy是一项非常繁重的操作,因此,如果可能,应避免使用。对于诸如以下的复杂结构,我们可以优化代码。

type Address struct {
    city  string
    state string
}

type Person struct {
    age     int
    name    string
    address []Address
}

p := Person{
    age:  20,
    name: "Jack",
    address: []Address{
        {
            city:  "city1",
            state: "state1",
        }, {
            city:  "city2",
            state: "state2",
        },
    },
}

var q Person
q.age = p.age
q.name = p.name
q.address = append(q.address, p.address...)
q.address[0].city = "cityx"

结果:

p object:
{20 Jack [{city1 state1} {city2 state2}]}

q object:
{20 Jack [{cityx state1} {city2 state2}]}

推断:
从上面的示例可以看出,当q改变时p对象没有改变。这种方法可用于嵌套的结构体数组。

答案 2 :(得分:0)

您可以使用带有按值传递的函数,并根据需要返回未更改或更改的参数。

使用上面的结构:

func main() {
    copyOf := func(y Person) Person {
        y.name = "Polonius"
        y.address = append(y.address, Address{
            city:  "other city",
            state: "other state",
        })
        return y
    }

    p := Person{
        age:  20,
        name: "Jack",
        address: []Address{
            {
                city:  "city1",
                state: "state1",
            }, {
                city:  "city2",
                state: "state2",
            },
        },
    }

    q := copyOf(p)

    fmt.Printf("Orig %v, \naddrss: %p \n\n", p, &p)
    fmt.Printf("Copy %v, \naddress: %p\n\n", q, &q)
}

答案 3 :(得分:-1)

小心,如果你的源 struct 实际上是一个指针,那么正常的赋值将不起作用:

package main
import "net/http"

func main() {
   a, e := http.NewRequest("GET", "https://stackoverflow.com", nil)
   if e != nil {
      panic(e)
   }
   b := a.URL
   b.Host = "superuser.com"
   println(a.URL.Host == "superuser.com")
}

相反,您需要取消引用指针:

package main
import "net/http"

func main() {
   a, e := http.NewRequest("GET", "https://stackoverflow.com", nil)
   if e != nil {
      panic(e)
   }
   b := *a.URL
   b.Host = "superuser.com"
   println(a.URL.Host == "stackoverflow.com")
}