3

I want to explore something about how the memory is allocated when we try to copy a variable. I did some tests and this one confuses me:

func testArrayAddress() {
    var a [3]int
    b := a
    fmt.Printf("address of a %p and of b %p \n", &(a[0]), &(b[0]))
}

The output is:

address of a 0xc8200126e0 and of b 0xc820012700

However as I assume a and b and pointing to the same array so the starting address of the first element should be the same?

This made me doubt that what happened when we exec the statement b := a? Originally I thought it will just allocate one memory block for the array when we init variable a, and b := a makes b pointing to the same memory location, but then it cannot explain why the address of the first element is not the same (which should be same element).

I changed the first line of code:

func testArrayAddress() {
    var a = []int{1, 2, 3}
    b := a
    fmt.Printf("address of a's first element %p and of b %p \n", &(a[0]), &(b[0]))
}

Then the output is:

address of a's first element 0xc8200126e0 and of b 0xc8200126e0

It gives me the same result now.

The question I want to ask are:

  1. In Golang when we do variable copy (b := a), are we also creating a copy of data in the memory? And is it the same for both immutable and mutable type?

  2. If we are copying for mutable type (eg. array) as well, how it manages to achieve modifying variable will also affects others (a[0] = 42 will affect b[0])?

  3. How is []int type different from [number]int type which I tested in the last case?

icza
  • 389,944
  • 63
  • 907
  • 827
Yuguang
  • 125
  • 5
  • 2
    This is all explained very nice in the Tour of Go (https://tour.golang.org) and the blog posts about arrays https://blog.golang.org/slices and slices https://blog.golang.org/go-slices-usage-and-internals. Short answer: `b := a` make a copy always. There are no immutable types in Go. 2) Undable with arrays, that's what slices are for. 3) `[]int` is a slice and `[3]int` an array. Please read https://tour.golang.org/moretypes/6 and the followig slides carefully. – Volker Nov 23 '16 at 10:59

1 Answers1

5

[3]int is an array, []int is a slice.

An array means all its elements, when passing it around or assigning it, all its elements are copied.

Slices are small, struct-like descriptors pointing to a contigous section of an underlying array. When passed around or assigned, only this header is copied (including the pointer), and so the "new" slice will point to the same backing array.

To answer your exact questions:

  1. Yes, b := a copies all elements if a is an array, but only the header if a is a slice. Both safe as long as only 1 goroutine accesses (modifies) a, and none is safe if multiple goroutines may modify it.

  2. If an array is copied, it will be completely independent from the "original", modifying the copy will have no effect on the original. If a slice is copied, the copy will point to the same backing array where the elements are stored. If you modify an element via the copy slice, you modify the one and only element, and so checking it via the original slice you will just check the only "instance" of the element (and observe the modified value).

  3. This is in the first sentence: []int is a slice, [n]int is an array.

See related questions:

Why have arrays in Go?
Golang passing arrays to the function and modifying it

Read the following blog posts for more details on slices and arrays:

Go Slices: usage and internals
Arrays, slices (and strings): The mechanics of 'append'

Community
  • 1
  • 1
icza
  • 389,944
  • 63
  • 907
  • 827