Consider the following programme (Go playground link). How is it that `multiplyByTwo` has amended the slice but `duplicate` hasn’t? How can a slice be both passed by reference (`multiplyByTwo`) and passed by value (`duplicate`) without using pointers?

``````func main() {
s := []int{1,2,3,4}

fmt.Println("before multiplyByTwo: ", s) // [1 2 3 4]

multiplyByTwo(s)

fmt.Println("after multiplyByTwo: ", s) // 2 4 6 8

duplicate(s)

fmt.Println("after duplicate: ", s) // 2 4 6 8
}

// multiplyByTwo accepts a slice of ints and multiplies each
// index by two.
func multiplyByTwo(s []int) {
for i, n := range s {
s[i] = n*2
}
}

// duplicate accepts a slice of ints and duplicates each entry
// exactly once
func duplicate(s []int) {
l := len(s)
for i:=0; i<l; i++ {
s = append(s, s[i])
}
}
``````

## A slice is not an array

While there are many similarities between arrays and slices (e.g. they can both be used with `len` and `cap`, and both types can be indexed), there are some fundamental differences.

``````
func main() {
slc := []int{1,2,3,4,5}
arr := int{1,2,3,4,5}

fmt.Printf("Slice length: %d, Slice Capacity: %d \n", len(slc), cap(slc)) // Slice length: 5, Slice Capacity: 5
fmt.Printf("Array length: %d, Array Capacity: %d \n", len(arr), cap(arr)) // Array length: 5, Array Capacity: 5

fmt.Printf("Slice First: %d \n", slc) // Slice First: 1
fmt.Printf("Array First: %d \n", arr) // Array First: 1
}
``````

Note: The following is not a comprehensive guide to the differences/similarities between arrays and slices, only enough to assist with the remainder of this article.

### Arrays

Arrays are fixed length. When declaring an array you state the size in-between the square brackets (`int{}`). When declaring the size, it becomes part of its type (e.g. `int` and `int` are different, incompatible types).

``````package main

func main() {
a := int{1,2,3,4,5}

// Some logic here

a = int{1,2,3} // Compilation Error: cannot use int{...} (type int) as type int in assignment
}
``````

### Slices

Slices are not fixed length, do not require an initial size on initialisation (though, one can be provided) and can be extended.

``````package main

import (
"fmt"
)

func main() {
a := []int{1,2,3}

fmt.Printf("len: (%d) cap: (%d) \n", len(a), cap(a)) // len: (3) cap: (3)

a = append(a, []int{4,5,6}...)

fmt.Printf("len: (%d) cap: (%d) \n", len(a), cap(a)) // len: (6) cap: (6)
}
``````

## Anatomy of a slice

First, let’s take a look at the slice struct.

``````type slice struct {
array unsafe.Pointer
len   int
cap   int
}
``````

Behind every slice is an array.

• The `len` field corresponds to the slice length (the number of elements the slice contains).
• The `cap` field corresponds to the slice capacity; the number of elements in the underlying array.

These fields do not always match.

``````package main

import (
"fmt"
"reflect"
"unsafe"
)

func main() {
// Create slice with length of 0 and capacity of 5
slc := make([]int, 0, 5)

printSlc(slc) // len: (0), cap: (5), array pointer: (824634232608)
}

func printSlc(slc []int) {
fmt.Printf("len: (%d), cap: (%d), array pointer: (%d) \n", len(slc), cap(slc), hdr.Data) // len: (0), cap: (5), array pointer: (0xc00000c030)
}
``````

Taking inspiration from the diagrams seen in the slices intro article, our `slc` slice looks like this: This is all important to understand because when the number of items in the slice (`len`) exceeds the capacity of the underlying array (`cap`) a new array needs to be created. The following example shows how the array pointer remains the same when the capacity is unchanged, but as soon as we append an additional item, exceeding the capacity, a new array is created with double the capacity and our array pointer changes to it.

``````package main

import (
"fmt"
"reflect"
"unsafe"
)

func main() {
// Create slice with length of 0 and capacity of 5
slc := make([]int, 0, 5)

printSlc(slc) // len: (0), cap: (5), array pointer: (824634232608)

/*
Append 5 new items to slc, which has an underlying array with a capacity of 5, so won't need
to create a new array.
*/
slc = append(slc, []int{1, 2, 3, 4, 5}...)

printSlc(slc) // len: (5), cap: (5), array pointer: (824634232608)

/*
Append a sixth item to slc, which will exceed the underlying arrays capacity and will result in a
new array being created with a capcity double what it was.
*/
slc = append(slc, 6)

printSlc(slc) // len: (6), cap: (10), array pointer: (824635408384)
}

func printSlc(slc []int) {
If the function doesn’t change the capacity of the underlying array (e.g. the earlier `multiplyByTwo` example), the changes will be persisted.