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

时间:2014-01-09 03:14:50

标签: 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
}

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

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

现在ab

相同

为什么以及如何直接将*b复制到*a

4 个答案:

答案 0 :(得分:69)

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

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

*a = *b;

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

从技术上讲,字符串总是指针,所以它们永远不会被复制为结构的一部分。 但是因为字符串是不可变的(并且Go有垃圾收集),字符串“感觉”就像它们是你的结构的一部分,并且你不必担心神奇地保存的低级字符串共享你记忆中没有你不得不考虑它。

答案 1 :(得分: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)

希望这是有道理的,这里有一个例子,你的应用被修改为“做正确的事情”。请注意,此处不需要您的复制功能,它可以用于说明。 Play example

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)
}

答案 2 :(得分:13)

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

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()
    }
}

所以:

CloneValue(old, new)
see this code in play.golang.org

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

答案 3 :(得分:0)

这是错误的。它不起作用

func (r *Request) WithContext(ctx context.Context) *Request {
  if ctx == nil {
    panic("nil context")
  }
  r2 := new(Request)
  *r2 = *r
  r2.ctx = ctx
  return r2
}