【问题标题】:Deep copy vs shallow copy for structs结构的深拷贝与浅拷贝
【发布时间】:2022-01-15 23:46:45
【问题描述】:

在传递带有原始和指针字段的结构时,我深入研究了一些关于深拷贝或浅拷贝的比较。喜欢:

type Copy struct {
    age int
    ac  *AnotherCopy
}

type AnotherCopy struct {
    surname string
}

func main() {
    s := Copy{
        age: 20,
        ac:  &AnotherCopy{surname: "Relic"},
    }
    passIt(&s)
    fmt.Printf("main s: %p\n", &s)
}

func passIt(s *Copy) {
    f := *s
    fmt.Printf("s: %p\n", &*s)
    fmt.Printf("f: %p\n", &f)

    f.age = 26
    f.ac.surname = "Walker"
    fmt.Printf("%v %s\n", f, f.ac.surname)
    fmt.Printf("%v %s\n", *s, s.ac.surname)
}

结果是

s: 0xc000010230
f: 0xc000010250
{26 0xc000010240} Walker
{20 0xc000010240} Walker
main s: 0xc000010230

我在这里看到的是,当我们传递一个包含原始类型和复合类型的结构时,它会深度复制原始类型并浅层复制指针(引用)字段。

我已经阅读了一些关于该过程的文章,但想法之间存在冲突。

问题是我们应该怎样称呼这个过程?深拷贝还是浅拷贝? 如果我们把这个过程称为只是浅拷贝,这是错的吗? 你能澄清一下吗?

【问题讨论】:

  • 这里没有“深拷贝”,go中的所有赋值都是简单的浅拷贝。我们称这个过程为“复制”
  • 好吧,为什么年龄字段的变化没有反映到原始变量。浅拷贝是否意味着对 f 字段的更改也应该更改 s 的字段,就像这里解释的那样:stackoverflow.com/a/184780/11156237“以后对其中任何一个内容的修改会立即反映在另一个内容中,因为它们共享内容。”
  • 在复制操作之后,您以两个包含指向相同姓氏值的指针的值结束。当您取消对姓氏的引用以更改/读取其值时,您将访问两个结构实例共享的指针所寻址的内存。这里没有什么需要澄清的。这就是它的设计方式。

标签: go deep-copy shallow-copy


【解决方案1】:

在您的问题中,您提到“原始类型和复合类型”是不同的,我认为这是您在这里感到困惑的根源。 Go 不区分原始类型和复合类型,而是区分指针类型和值类型。 “原始”类型(intint32float64 等)是值类型,但 structs(以及数组)也是如此。指向其他类型、映射、切片、通道和接口的指针都是指针类型。

您的问题的直接答案是,正如一条评论所述,Go 中的副本(通过变量赋值等)是“浅副本”,因为 Go 不会取消引用指针类型并创建新的底层副本。然而,由于struct 类型的东西不是指针类型,复合值完全有可能被“深度复制”。

如果您想看到这一点,请尝试修改您的示例代码,使您的 Copy 类型上的 ac 字段是一个普通结构而不是指向结构的指针:

type Copy struct {
    age int
    ac  AnotherCopy
}

然后您应该看到创建Copy 的副本并设置ac.surname 字段不会更改原始结构上ac.surname 字段的值。

【讨论】:

  • pkg.go.dev/go/types#BasicKind 。可能存在指向 struct 的 ptr。 maps, slices, channels, and interfaces are all pointer types.,据我了解,它们是包含指向某些内存的指针的值。通常它们被称为切片头、映射头等pkg.go.dev/reflect#SliceHeaderresearch.swtch.com/interfaces Interface values are represented as a two-word pair giving a pointer to information about the type stored in the interface and a pointer to the associated data. 这整个事情很微妙,我希望我能帮助澄清
猜你喜欢
  • 2011-02-09
  • 2012-04-12
  • 2015-01-13
  • 2011-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-14
相关资源
最近更新 更多