In this blog, we will take a look at Arrays and Slices in Golang or The Go Programming Language.
Let’s see what we will be learning.
Arrays and Slices in Golang or Go Language:
- Creation of Arrays and Slices
- Built-in functions in Arrays and Slices
- How to work with Arrays and Slices
Before starting this topic must read the previous topics:
The need for Arrays in Language
Arrays are containers of values in a programming language, it gives continuous memory blocks to the variables and it’s easy to access.
Let’s assume that an Integer value takes 4 bytes of memory. So in order to store many integer values in contiguous memory blocks and the memory will be allocated with a difference of 4 bytes.
We can access any element in the array using the index and one important thing to notice here is the index starts with 0 and not 1.
Arrays have a constant look up time.
Example from the Picture above (name of the Array – arr):
fmt.Println(arr[0])
fmt.Println(arr[1])
fmt.Println(arr[2])
fmt.Println(arr[3])
Output:
15
24
30
45
Golang Make Array
package main
import (
"fmt"
)
func main() {
var arr = [8]int{15, 24, 30, 45, 56, 12, 34, 19}
fmt.Println(arr)
}
Output:
[15 24 30 45 56 12 34 19]
If you look at the program or the Array creation Image, you will find that we have declared the size of the array two times, which is unnecessary.
Another way to declare arrays when you want to declare it with values is:
package main
import (
"fmt"
)
func main() {
var arr = [...]int{15, 24, 30, 45, 56, 12, 34, 19}
fmt.Println(arr)
}
Output: – Same Output as above.
Golang Arrays Declaration
var arr [5]string
package main
import (
"fmt"
)
func main() {
var names [5]string
fmt.Println("Names ", names)
}
Output:
Names [ ]
Golang Arrays Mutable
Earlier we had declared empty array and we can now fill it with values using indexes, this makes arrays mutable.
package main
import (
"fmt"
)
func main() {
var names [5]string
names[0] = "Divyanshu Shekhar"
fmt.Println("Names ", names)
}
Output:
Names [Divyanshu Shekhar ]
We need not to fill the values continuously. Order doesn’t matter while filling up the values.
Example:
package main
import (
"fmt"
)
func main() {
var names [5]string
names[0] = "Divyanshu Shekhar"
names[2] = "Shubham Ranjan"
names[1] = "Arpit Sahu"
fmt.Println("Names ", names)
}
Output:
Names [Divyanshu Shekhar Arpit Sahu Shubham Ranjan ]
Golang Arrays Built-in Functions
Let’s see Built in Functions in Golang Arrays.
Golang Array length
len(<array_name>)
package main
import (
"fmt"
)
func main() {
var names [5]string
names[0] = "Divyanshu Shekhar"
names[2] = "Shubham Ranjan"
names[1] = "Arpit Sahu"
fmt.Println("Length of names Array: ", len(names))
}
Output:
Length of names Array: 5
Golang 2D Arrays
package main
import (
"fmt"
)
func main() {
var matrix [3][3]int = [3][3]int{[3]int{1, 2, 3}, [3]int{4, 5, 6}, [3]int{7, 8, 9}}
fmt.Println("2D Array:", matrix)
fmt.Println("Length of 2D Array:", len(matrix))
}
2D Array in Golang can also be filled using indexes.
matrix[0] = [3]int{1, 2, 3}
matrix[1] = [3]int{4, 5, 6}
matrix[2] = [3]int{7, 8, 9}
Output:
2D Array: [[1 2 3] [4 5 6] [7 8 9]]
Length of 2D Array: 3
Golang array copy
In other languages, arrays are considered as pointers that point to the memory block holding that specific value, but in Golang Arrays are considered as values.
When copying an array to another array in other languages like c/c++/python, the language used to pass a reference to the array, and any changes made in the copied array used to change the original array.
package main
import (
"fmt"
)
func main() {
var a = [...]int{15, 24, 30, 45, 56, 12, 34, 19}
b := a
a[1] = 100
fmt.Println("a : ", a)
fmt.Println("b : ", b)
}
Output:
a : [15 100 30 45 56 12 34 19]
b : [15 24 30 45 56 12 34 19]
But, In Golang as arrays are values it gets fully copied to another variable of array type, and any changes made in the copied array don’t reflect on the original array.
Golang Pointers
We can also pass the same array to the another array variable using pointers. We pass the memory address of the array to the next array and thus both the variables can access the same variable.
In this case any of the variable can potentially change the value in the array.
b := &a
package main
import (
"fmt"
)
func main() {
var a = [...]int{15, 24, 30, 45, 56, 12, 34, 19}
b := &a
a[1] = 100
fmt.Println("a : ", a)
fmt.Println("b : ", b)
}
Output:
a : [15 100 30 45 56 12 34 19]
b : &[15 100 30 45 56 12 34 19]
Golang Slices
a := []<datatype>{<values>}
Slices in Golang are almost the same as Arrays, the only difference is we had to pass size inside the square braces in an Array creation or three dots (…), but while slice creation we neither have to pass the size of the array nor three dots (…).
package main
import (
"fmt"
)
func main() {
var a = []int{15, 24, 30, 45, 56, 12, 34, 19}
fmt.Printf("%v,%T", a, a)
fmt.Println("Length of Slice a : ", len(a))
}
Output:
[15 24 30 45 56 12 34 19],[]int
Length of Slice a : 8
Golang Slice Capacity
var a = [8]int{15, 24, 30, 45, 56, 12, 34, 19}
fmt.Println("Capacity of Slice a : ", cap(a))
Output:
Capacity of Slice a : 8
Golang Slice Append
The append function takes the slice in which the values are to be appended.
package main
import (
"fmt"
)
func main() {
var a = []int{}
a = append(a, 2, 3, 4, 5)
fmt.Println(a)
fmt.Println("Length of the array a: ", len(a))
fmt.Println("Capacity of the array a: ", cap(a))
}
Output:
[2 3 4 5]
Length of the array a: 4
Capacity of the array a: 4
Golang Spread Operator
First take a look without spread operator.
var b = []int{2, 3, 4, 5, 6, 7, 8}
a = append(a, b)
Error:- cannot use b (type []int) as type int in append
Using Spread Operator
package main
import (
"fmt"
)
func main() {
var a = []int{}
var b = []int{2, 3, 4, 5, 6, 7, 8}
a = append(a, b...)
fmt.Println(a)
fmt.Println("Length of the array a: ", len(a))
fmt.Println("Capacity of the array a: ", cap(a))
}
Output:-
[2 3 4 5 6 7 8]
Length of the array a: 7
Capacity of the array a: 8
Append Function doesn’t work with Golang arrays
package main
import (
"fmt"
)
func main() {
var a = [...]int{}
a = append(a, 2, 3, 4)
fmt.Println(a)
fmt.Println("Length of the array a: ", len(a))
fmt.Println("Capacity of the array a: ", cap(a))
}
Error:- first argument to append must be slice; have [0]int
Golang Slice of Slices
These slicing operations can also be done on Arrays in Golang.
package main
import (
"fmt"
)
func main() {
var a = [8]int{15, 24, 30, 45, 56, 12, 34, 19}
b := a[:]
c := a[2:]
d := a[:5]
e := a[2:5]
fmt.Println("b : ", b)
fmt.Println("c : ", c)
fmt.Println("d : ", d)
fmt.Println("e : ", e)
}
1. a[:]
This will slice all the values of the array ‘a’.
2. a[2:]
This will start slicing from the second index and will slice all the way to end.
3. a[:5]
This will start slicing from the start and will last at the 4th index (Excluding 5th index).
4. a[2:5]
This will start slicing from the second index and will slice till the 4th index (Excluding the 5th index).
Golang Slicing
1. Slicing element from start
var a = []int{1, 2, 3, 4, 5, 6, 7, 8}
fmt.Println(a[1:])
Output: – [2 3 4 5 6 7 8]
2. Slicing element from end
var a = []int{1, 2, 3, 4, 5, 6, 7, 8}
fmt.Println(a[:len(a)-1])
Output:- [1 2 3 4 5 6 7]
3. Slicing element from middle
var a = []int{1, 2, 3, 4, 5, 6, 7, 8}
a = append(a[:2], a[5:]...)
fmt.Println(a)
Output:- [1 2 6 7 8]
Golang Slice vs Array
1. Golang Slices Reference type
Do you remember copying of array discussed above?
When we used to initialize one array to another array, it used to get fully copied and any changes made in the copied array didn’t affect the original array.
But slices in Golang are reference types and it passes the memory location of the array and both the variables access the same array and can change the values of the array.
package main
import (
"fmt"
)
func main() {
// Slices in Golang
var a = []int{15, 24, 30, 45, 56, 12, 34, 19}
b := a
a[1] = 100
fmt.Println("a : ", a)
fmt.Println("b : ", b)
}
Output:
a : [15 100 30 45 56 12 34 19]
b : [15 100 30 45 56 12 34 19]
Output:
b : [15 24 30 45 56 12 34 19]
c : [30 45 56 12 34 19]
d : [15 24 30 45 56]
e : [30 45 56]
Golang Slice Make
make(<type_object>, <length>,<capacity>)
package main
import (
"fmt"
)
func main() {
var a = make([]int, 5, 100)
fmt.Println("a :", a)
fmt.Println("Length of Slice a :", len(a))
fmt.Println("Capacity of Slice a :", cap(a))
}
Output:
a : [0 0 0 0 0]
Length of Slice a : 5
Capacity of Slice a : 100
Golang Slices Make Function
When we don’t make slice using make function, we are not able to specify the capacity of the slice and the compiler takes the charge of increasing capacity of the slice in Golang.
package main
import (
"fmt"
)
func main() {
var a = []int{}
fmt.Println(a)
fmt.Println("Length of the array a: ", len(a))
fmt.Println("Capacity of the array a: ", cap(a))
for i := 0; i < 33; i++ {
a = append(a, i)
fmt.Println(a)
fmt.Println("Length of the array a: ", len(a))
fmt.Println("Capacity of the array a: ", cap(a))
}
}
Output:-
[]
Length of the array a: 0
Capacity of the array a: 0
[0]
Length of the array a: 1
Capacity of the array a: 1
[0 1]
Length of the array a: 2
Capacity of the array a: 2
[0 1 2]
Length of the array a: 3
Capacity of the array a: 4
[0 1 2 3]
Length of the array a: 4
Capacity of the array a: 4
[0 1 2 3 4]
Length of the array a: 5
Capacity of the array a: 8
.
.
Length of the array a: 8
Capacity of the array a: 8
[0 1 2 3 4 5 6 7 8]
Length of the array a: 9
Capacity of the array a: 16
.
.
.
.
.
.
[0 1 2 3 …….. 12 13 14 15]
Length of the array a: 16
Capacity of the array a: 16
[0 1 2 3 ……. 12 13 14 15 16]
Length of the array a: 17
Capacity of the array a: 32
.
.
.
[0 1 2 3 4 5 6
[0 1 2 ……. 27 28 29 30 31]
Length of the array a: 32
Capacity of the array a: 32
[0 1 2 3 ……. 30 31 32]
Length of the array a: 33
Capacity of the array a: 64
We see a pattern in the increase of the capacity of the slice i.e each time the capacity is full it is multiplied by 2 and the capacity is increased.
When the value of the variable ‘i’ increases to 32, the length of the slice becomes 33 which is greater than the previous capacity of the slice and thus multiplies by 2 (32 x 2), and the capacity increases to 64.
This can occupy unnecessary memory in our program, so it’s better to take control of your memory by making slices using make function. You can pass the capacity of the slice and this will lead to memory management in your program.
Read Why Golang is called the future of server-side language?
Learn more about Arrays and Slices in Golang from Official Documentation.