Sign in
Log inSign up

Difference b/w Slice and Array Golang

Ruchi Vashisht's photo
Ruchi Vashisht
·Aug 21, 2021·

4 min read

This is a very basic but frequently asked question in Golang interviews. I have observed that many people fail to answer this correctly. I have seen many people using these in their code without actually understanding how they work behind the camera.

Arrays

Arrays is a collection of fixed number of same type of elements. While creating an array, size is always the part of type itself. Just like you cannot assign a string value to integer value, you cannot use arrays of different sizes interchangeably.

func main() {
    var arr1 = [4]int{1,2,3,4}
    var arr2 [6]int
    arr2 = arr1
    fmt.Println(arr2)
}

Output

./prog.go:12:7: cannot use arr1 (type [4]int) as type [6]int in assignment

In the above code, I first created an array arr1 of type [4]int. Then I created another array arr2 of type [6]int. These two are different types because sizes are different so I cannot assign arr1 to arr2. Hence the error. Arrays are fixed in length, and its length cannot be changed at runtime. Below code snippet will throw an error

func main() { 
    var arr [10]int
    fmt.Println(arr)
    arr = append(arr , 1)
    fmt.Println(arr)
}

Output

./prog.go:10:14: first argument to append must be slice; have [10]int

Only use case of arrays in real programs is when you know exactly the size of your array. Otherwise slices are used most of the time which are more convenient to use.

Slices

Slices are just a wrapper around arrays. They help you do some operations on top of arrays. When I say wrapper, I mean that they do not hold any value itself, they reference an underlying array on which they perform operations.

While creating a slice, you do not specify the size. This is the key difference between arrays and slices.

var s []int

Length and Capacity of a Slice

Slices can also be created using built-in make function

func make([]T, len, cap) []T

Here T is type of elements, length is for current count of elements and capacity is maximum elements it can hold. When this function is called, it creates an array and returns a slice which refer this array. Slice holds three values , a pointer to first element of array, length and capacity. Capacity field is optional, when not specified its picks the value of length.

func main() {
    arr := make([]int, 5, 10)
    fmt.Printf("Array: %v, capacity: %d, length: %d", arr, cap(arr), len(arr))
}

Output

Array: [0 0 0 0 0], capacity: 10, length: 5

What happens when we try to add element to slice when its capacity is full

func main() {
    arr := make([]int, 5, 6)
    fmt.Printf("Array: %d, Address: %p, capacity: %d, length: %d \n", arr, &arr[0], cap(arr), len(arr))
    arr = append(arr, 1)
    fmt.Printf("Array: %d, Address: %p, capacity: %d, length: %d \n", arr, &arr[0], cap(arr), len(arr))
    arr = append(arr, 1)
    fmt.Printf("Array: %d, Address: %p, capacity: %d, length: %d \n", arr, &arr[0], cap(arr), len(arr))
}

Output

Array: [0 0 0 0 0], Address: 0xc0000b2030, capacity: 6, length: 5 
Array: [0 0 0 0 0 1], Address: 0xc0000b2030, capacity: 6, length: 6 
Array: [0 0 0 0 0 1 1], Address: 0xc000094060, capacity: 12, length: 7

First I created a slice with length of 5 and capacity of 6. It means that one more element can be added to underlying array. We can see the address of underlying array by printing the address of its first element. When I appended one element, it added that to the same underlying array. Next, when I tried to append one more element, at that point its capacity was full so it created another array and copied all the values from previous array into it and doubled its capacity and started referencing to it instead. You can see the change in address of underlying array.

Creating a slice from an existing array

You can create a slice from an existing array using : descriptor.

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

    s := arr[:]

    fmt.Println(arr)
    fmt.Println(s)
}

Output:

[1 2 3 4 5]
[1 2 3 4 5]

You can also select a part of an array instead by providing the start and end index. If you don't provide any indices it will reference the entire array. Index provided before the colon is inclusive but index provided after the column is exclusive. It means if you say arr[1:4], it will pick from index 1 up to index 3. See below snippet for examples

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

    s1 := arr[:] // all elements

    fmt.Println(s1)

    s2 := arr[2:4] // starting index 2 , upto index 3
    fmt.Println(s2)

    s3 := arr[2:] // starting index2 , upto last element
    fmt.Println(s3)

    s4:= arr[:4] // starting index 0, upto index 3
    fmt.Println(s4)


}

Output

[1 2 3 4 5]
[3 4]
[3 4 5]
[1 2 3 4]

If you want to get more deeper understanding of these concepts and internal workings, Please head out to below links.