Hey there!
This blog is all about arrays in Golang. I've already made an intro kind of thing where I explained a little bit about the arrays of Golang. Now we'll dig a bit deep into arrays.
Array
An array is a contiguous storage data structure, which means, it stores elements sequentially in memory. By now I assume you know how indexing works, let's see how elements store in memory.
For example: var arr = [12]int{11, 9, 17, 89, 1, 90, 19, 5, 3, 23, 43, 99}
The above representation says that, if the first element 11
is stored at the memory location 200
then the second element 9
is stored at 204
memory location, and so on.
You might be wondering if 11
is stored at 200
why not 9
starts at 201
instead of 204
, because if you can remember an int would typically take 4 bytes
(assuming int32). That's why the memory locations are multiples of 4. If we use int64 then the memory locations would look like 200, 208, 216, 224, etc.
You might again be thinking why 11
stored at 200
memory location where it could have started from the beginning, like 1
location or 0
location. To be honest 200
is just to represent some memory location, in practice, it is random, execution engine of a language takes care of these operations like memory allocation and deallocation.
One more important note, arrays can only store homogeneous elements, meaning, elements of same type. If we declare the type to be int, we can not store other types of data.
package main
import "fmt"
func main(){
var someArray [2]int = [2]int{100, "John"} // raises an error
}
Various ways to Declare and initialize arrays
Array Literal
package main
import "fmt"
func main(){
var arr [2]int = [2]int{100,200}
fmt.Println(arr) // prints [100 200]
}
The above declaration is called array literal as we are assigning the values right away when we are declaring the variable.
Declare and Initialize later
package main
import "fmt"
func main(){
var arr [2]int
arr[0] = 10
arr[1] = 20
fmt.Println(arr[0]) // prints 10
}
The above code says that declare a variable arr
with type int and of size 2, [2]int
Later, we're assigning the array's 0th index to 10
and 1st index to 20
.
Remember, when we're declaring var arr [2]int
, the compiler is creating a arr
variable and setting up the size 2 for that variable, and assigning the default value 0
(int default value is 0) to the whole size of that array.
package main
import "fmt"
func main(){
var arr [2]int
fmt.Println(arr) // prints [0 0]
}
Initialize with ellipses
package main
import "fmt"
func main(){
arr := [...]int{10, 20}
fmt.Println(arr) // prints [10 20]
}
Instead of declaring its size, we could use three dots ...
known as ellipses. The compiler would know the size of the array by the number of elements provided while declaring it.
Methods of Arrays
len() --> returns the size of an array(number of elements in array)
cap() --> returns the capacity of an array(number of elements it can hold)
As the size of an array is static i.e fixed, so both len() and cap() are gonna be same.
package main
import "fmt"
func main(){
arr := [5]int{10, 20, 30, 40, 50}
fmt.Println(len(arr)) // prints 2
fmt.Println(cap(arr)) // prints 2
var arr2 [10]int
fmt.Println(arr2) // prints [0 0 0 0 0 0 0 0 0 0]
fmt.Println(len(arr)) // prints 10
}
Copying arrays
To copy arrays we would assign one array variable to other.
package main
import "fmt"
func main(){
arr := [5]int{10, 20, 30, 40, 50}
arr2 := arr
fmt.Println(arr2) // prints [10 20 30 40 50]
}
The above copying is done as pass by value. Whatever elements are there in arr
have been copied to arr2
. We can even copy using pass by reference technique.
package main
import "fmt"
func main(){
arr := [5]int{10, 20, 30, 40, 50}
arr2 := &arr
fmt.Println(*arr2) // prints [10 20 30 40 50]
arr2[0] = 96
fmt.Println(*arr2) // prints [96 20 30 40 50]
fmt.Println(arr) // prints [96 20 30 40 50]
}
If you've noticed &arr
, the symbol & is known as ampersand, used to refer to the actual address of the variable rather than value. So, the new variable arr2
wiil still refers to the values of arr
. Now modifications made to arr2
will be reflected in arr
too.
Note: Variables arr2
is now a pointer, in order to get the values in a pointer variable, we use *, to deference and get the values.
Iterating over array
We can iterate(traverse) over the array elements in order to access elements. For this, we use for loop
package main
import "fmt"
func main(){
arr := [3]int{10, 20, 30}
for i := 0; i<len(arr); i++ {
fmt.Println(arr[i])
}
}
// output
10
20
30
We can also use range keyword.
package main
import "fmt"
func main(){
arr := [3]int{10, 20, 30}
for i, ele := range arr {
fmt.Println(i,ele)
}
}
// output
0 10
1 20
2 30
As you can see in the output, the range keyword returns us both the index and element. If we don't care about index, we can just use undersore _
which ignores that variable.
Array slicing
Slicing basically means cutting and getting the required portion of an array. Let's say we have an arrayarr := [5]int{1, 2, 3, 4, 5}
, and we want to get the first 3 elements 1, 2, 3
, in this case, we can iterate over the array and get the three elements. But with slicing, that could be done in a single statement/expression
arr := variable[start:end(excluded)]
package main
import "fmt"
func main(){
arr := [5]int{1, 2, 3, 4, 5}
arr2 := arr[0:3]
// 0 3
// [ 1, 2, 3, 4, 5]
fmt.Println(arr2) // prints [1 2 3]
}
Just like we access elements of the array using the index, this time we would provide two indexes, a starting index and an ending index. The elements ranging over these indexes will be returned as a slice.
If you've noticed, the last element 4, which is at index 3 is not returned, because the ending index is excluded. Thus returning [1 2 3]
and we stored them in arr2
variable.
There are default values for both the start and end index, if not provided.
The start index defaults to 0, and the end index defaults to the length of an array
package main
import "fmt"
func main(){
arr := [5]int{1, 2, 3, 4, 5}
arr2 := arr[3:]
// 3
// [ 1, 2, 3, 4, 5]
fmt.Println(arr2) // prints [4 5]
arr3 := arr[:2]
// 2
// [ 1, 2, 3, 4, 5]
fmt.Println(arr3) // prints [1 2]
arr4 := arr[:]
fmt.Println(arr4) // prints [1 2 3 4 5]
}
As I mentioned, when we slice an array arr2 := arr[3:]
, we get a slice, not an array.
What is a slice? you may ask. A slice is like an array but doesn't get limited by its size like an array.
Learn more about slices https://mohanj.hashnode.dev/golang-slices
That's it. Will add more details if found anything worth including. Till then, peace out!