copy pointer values *a = *b in golang

Go

Go Problem Overview


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 is still empty, I have to do it like this

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

now a is the same as b

Why and how can I copy *b to *a directly?

Go Solutions


Solution 1 - Go

Your first example is almost right. You pass in pointers to two objects. You put those pointers into variables A and B. But A and B are local variables, so when you say a=b you are merely saying "forget what was in A (locally)". The rest of the program still has pointers to those two original objects.

If you want to copy the data structure at B into the data structure at A, do this instead:

*a = *b;

As dmikalova pointed out in the comments below, this merely copies the structs -- but not any data the struct points to. If your struct has a pointer, the data it points to is now shared by the two copies (because it only copied the pointer).

Technically, strings are always pointers, so they are never copied as part of your struct. But because strings are immutable (and Go has Garbage Collection), strings "feel" like they are part of your struct, and you don't have to worry about the low-level string sharing that magically saves you memory without you having to think about it.

Solution 2 - Go

Generic solution for framework developers :

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

So:

Copy(old, new)

So you can pass any type at run time as long as you're sure that source and destin are both of the same type, (and destin is a pointer to that type).

Solution 3 - Go

In go, arguments are passed by value.

and *T is a pointer to a T. Think of it as an int that tells you where that T is. So, "a" points to one instance of T and b points to another.

in your copy function, you are saying make a point to b's "T" (if that made sense). What you wanted was to say that a's T should be the same as b's T

You do that by dereferencing the pointers.

so, instead of a = b (change my local variable "a" to point to whatever "b" points to) you use *a = *b (change a's T to be equal b's T)

Hopefully that made sense, here's an example of your app modified to "do the right thing". Note, your Copy function isn't necessary in this, it's there for illustration. 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)
}

Solution 4 - Go

This is wrong.It does not work

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGert CuykensView Question on Stackoverflow
Solution 1 - GoBraveNewCurrencyView Answer on Stackoverflow
Solution 2 - GoMohsenView Answer on Stackoverflow
Solution 3 - GoDavid BudworthView Answer on Stackoverflow
Solution 4 - GoHua zhangView Answer on Stackoverflow