I have some issues with managing structs in Go. I have complex struct and two variables based on that struct - "previous" and "current". I'm trying to read data from tarfile, do some calculations and replace previous with current. But at next iteration of reading when I read to current, it seems to me, a content of "previous" overwritten and both variables become the same. Struct defined as follows:
type Mystruct struct {
Data [][]sql.NullString
Rnames []string
Nsize int
Msize int
Namemaxlen map[string]int
Valid bool
Err error
}
Variables are not pointers. Copy performs as direct assignment: previous = current.
tr := tar.NewReader(f)
var prev, curr Mystruct
for {
hdr, err := tr.Next()
if err == io.EOF {
break
} else if err != nil {
log.Panicln(err)
}
data := make([]byte, hdr.Size)
if _, err := io.ReadFull(tr, data); err != nil {
log.Panicln(err)
}
if err = json.Unmarshal(data, &curr); err != nil {
log.Panicln(err)
}
if prev.Valid != true {
prev = curr
continue
}
// other computations here
prev = curr
}
Where do I wrong? Thanks in advance.
The problem is that your struct contains slices which are basically pointers to memory. Copying those pointers means that your copy points to the SAME memory as the original, thus they share the slice values. Changing one changes the other.
Here is a small example to illustrate the problem:
package main
import "fmt"
type s struct {
a int
slice []int
}
func main() {
// create the original thing
prev := s{
a: 5,
slice: []int{1, 2, 3},
}
// copy the thing into cur
cur := prev
// now change cur, changing a will change only cur.a because integers are
// really copied
cur.a = 6
// changing the copied slice will actually change the original as well
// because copying a slice basically copies the pointer to memory and the
// copy points to the same underlying memory area as the original
cur.slice[0] = 999
// printing both, we can see that the int a was changed only in the copy but
// the slice has changed in both variables, because it references the same
// memory
fmt.Println(prev)
fmt.Println(cur)
}