在golang中复制指针值*a =*b

Ger*_*ens 42 go

type T struct {
    Id int
    Name string
}

func Copy(a *T, b *T) error {
    b.Id=5
    b.Name="gert"
    a = b
    return nil
}
Run Code Online (Sandbox Code Playgroud)

a 仍然是空的,我必须这样做

func Copy(a *T, b *T) error {
    b.Id = 5
    b.Name = "gert"
    a.Id = b.Id
    a.Name = b.Name
    return nil
}
Run Code Online (Sandbox Code Playgroud)

现在a是一样的b

为什么我怎么能复制*b*a直接?

Bra*_*ncy 71

你的第一个例子几乎是对的.您将指针传递给两个对象.你把这些指针放在变量A和B中.但A和B是局部变量,所以当你说a=b你只是说"忘记A(本地)中的内容"时.程序的其余部分仍然指向这两个原始对象.

如果要将B处的数据结构复制到A 处的数据结构中,请执行以下操作:

*a = *b;
Run Code Online (Sandbox Code Playgroud)

正如dmikalova在下面的评论中所指出的,这只是复制结构 - 但不是结构所指向的任何数据.如果你的struct有一个指针,它指向的数据现在由两个副本共享(因为它只复制了指针).

从技术上讲,字符串总是指针,所以它们永远不会被复制为结构的一部分.但是因为字符串是不可变的(并且Go具有垃圾收集),字符串"感觉"就像它们是你的结构的一部分,并且你不必担心低级别的字符串共享,它可以神奇地节省你的记忆,而你不必考虑关于它.

  • 大声笑:)尝试了`a =*b`和`*a = b`以及我在标题中键入的内容`*a =*b`我没有哈哈 (15认同)
  • 你可能对它有一个惊喜是它是一个浅拷贝 - 所以如果b上的任何字段都是指针那么它就是那些将被复制到a的指针.任何地图或结构都不会被深深复制. (3认同)
  • 这实际上是复制数据结构,还是只设置指针a指向与指针b相同的位置?在这个任务之后,b的变化也会发生在?如果是这样,那不是复制,而是简单的分配. (2认同)
  • 阅读我写的内容.`*a =*b`将数据从一个结构的内存(由b指向)复制到另一个结构的数据上(由a指向).它们仍然是不同的内存区域,因此更新不会传播. (2认同)
  • @NielsAbildgaard你首先假设`a!= b`,所以`*a`和`*b`在内存的不同位置.赋值`*a =*b`不会修改`a`或`b`,所以你最终得到`*a ==*b`但仍然有'a!= b`. (2认同)
  • 如果 `a == nil` 就会出现恐慌 (2认同)

Dav*_*rth 14

在go中,参数按值传递.

并且*T是指向T的指针.将它想象成一个int,告诉你T在哪里.因此,"a"指向T的一个实例,b指向另一个实例.

在你的复制功能中,你说的是指向b的"T"(如果这是有道理的).你想要的是说a的T应该与b的T相同

你通过解除引用指针来做到这一点.

所以,而不是a = b(改变我的局部变量"a"指向任何"b"点)你使用*a =*b(将a的T改为等于b的T)

希望这是有道理的,这是一个你的应用程序修改为"做正确的事情"的例子.请注意,此处不需要您的复制功能,它可以用于说明. 播放示例

import "fmt"

type T struct {
    Id   int
    Name string
}

func Copy(a *T, b *T) error {
    b.Id = 5
    b.Name = "gert"
    a = b
    return nil
}
func CopyThatActuallyCopies(a *T, b *T) error {
    b.Id = 5
    b.Name = "gert"
    *a = *b
    return nil
}

func main() {
    var a = &T{1, "one"}
    var b = &T{2, "two"}

    fmt.Println(a, b)
    Copy(a, b)
    fmt.Println(a, b)
    CopyThatActuallyCopies(a, b)
    fmt.Println(a, b)
}
Run Code Online (Sandbox Code Playgroud)


Moh*_*sen 14

框架开发人员的一般解决方

func CloneValue(source interface{}, destin interface{}) {
    x := reflect.ValueOf(source)
    if x.Kind() == reflect.Ptr {
        starX := x.Elem()
        y := reflect.New(starX.Type())
        starY := y.Elem()
        starY.Set(starX)
        reflect.ValueOf(destin).Elem().Set(y.Elem())
    } else {
        destin = x.Interface()
    }
}
Run Code Online (Sandbox Code Playgroud)

所以:

CloneValue(old, new)
Run Code Online (Sandbox Code Playgroud) 请参阅play.golang.org中的此代码

所以你可以在运行时传递任何类型,只要你确定source和destin都是相同的类型,(并且destin是指向该类型的指针).

  • 你可以在投票否决之前对其进行测试。 (2认同)
  • 如何使用`reflect`的有用示例. (2认同)