Arrays in Go
An array is a fixed-length sequence of data items of the same type. It is a homogeneous data structure. This type can be anything from primitive types like integers or strings to self-defined types. The length must be a constant expression, that must evaluate a non-negative integer value.
Arrays in Go holds a fixed number of elements, and it cannot grow or shrink in size. The elements of the array are stored sequentially and can be accessed using their index. The index starts from 0, so the 1st element has index 0, the second element has index 1, and so on.
The number of items also called the length (called len) or size of the array, is fixed and must be given when declaring the array (length has to be determined at compile time in order to allocate the memory).
Array Syntax in Go
The format of the declaration of an array looks something like this:
var identifier [len]type
Consider the example shown below where we are just declaring an array and then printing it using the fmt.Println() function.
Example 1: Array Declaration
Here, we created an array arr of int type and can hold 3 values.
package main
import (
"fmt"
)
func main() {
var arr [3]int
fmt.Println(arr)
}
[0 0 0]
In the above example, we declared an array that contains integer values(int to be more precise).
When declaring an array, each item in it is automatically initialized with the default zero-value of the type. Here, all the items default to 0. The length is 3, and the index ranges from 0 to len(arr1)-1 (2 in this case). The first element is given by arr[0], and the 3rd element is given by arr[2]; in general, the element at index i is given by arr[i]. The last element is given by: arr[len(arr)-1].
It should be noted that an array's length is part of its value and cannot be resized.
Example: Find Array Type
Consider the example shown below that depicts an array and when we print the exact type of the array, we will get the length as part of the array itself.
package main
import (
"fmt"
"reflect"
)
func main() {
var arr [3]int
fmt.Println(arr)
fmt.Println(reflect.TypeOf(arr))
}
[0 0 0]
[3]int
Assigning a value to an array-item at index i, is done with:
arr[i] = value
Arrays are mutable, which means that they can be changed.
Only valid indexes can be used. When using an index equal to or greater than len(arr) and if the compiler can detect this, the message index out of bounds is given; otherwise, the code compiles just fine. Executing the program will give the runtime error: index out of range. A runtime error means the program will crash and give a certain message. In Go terminology, this is called a panic.
Assign and Access Array Elements
Now that we know how we can create an array in Go, let's explore a case where we want to assign some values to the array and then access those values later on. It is one of the most basic and yet important things to know when it comes to arrays.
Consider the example shown below.
package main
import (
"fmt"
)
func main() {
var arr [3]int
arr[0] = 1
arr[1] = 2
arr[2] = 3
fmt.Println(arr)
fmt.Println(arr[2])
}
[1 2 3]
3
Example: Multiple Assignment in Array
Instead of assigning one value at a time in a single line, we can assign multiple values in a single line.
package main
import (
"fmt"
)
func main() {
var arr [3]int
arr[0], arr[1], arr[2] = 1, 2, 3
fmt.Println(arr)
fmt.Println(arr[2])
}
[1 2 3]
3
Array literals
In Go, as we are declaring an array we can also set the entries in the array as well with the help of the literal values. Literal values are those values that are passed when declaring an array. This approach of array declaration is only useful when we know what exact elements we want in our array and how many of them are there in total.
Consider the example shown below that depicts an integer array where we are making use of the literals to declare the array and set the values as well.
package main
import (
"fmt"
)
func main() {
arr := [3]int{1,2,3}
fmt.Println(arr)
stringArr := [3]string{"abc","def","ghi"}
fmt.Println(stringArr)
}
In the above example, we declared two literal arrays, where one holds the integer values and the other holds the string values and then we are printing those arrays.
[1 2 3]
[abc def ghi]
Arrays with implicit length
In Go, when it comes to arrays it is almost a standard to provide the length of the array when you are declaring the array itself, but it should also be noted that we can provide the implicit length of the array with the help of ellipsis which is also a valid syntax for array declaration in Go.
Ellipsis is nothing but three dots(...) which can replace the array length keyword when we are declaring an array.
Consider the example shown below where we are declaring an array with an implicit length via ellipsis.
package main
import (
"fmt"
)
func main() {
arr := [...]int{1,2,3}
fmt.Println(arr)
stringArr := [...]string{"abc","def","ghi"}
fmt.Println(stringArr)
}
Please notice that in the example before the current one, we were making use of the number of elements in the array while defining the array but in the above example we simply printed the array without the length property and with the help of ellipsis.
[1 2 3]
[abc def ghi]
Printing Arrays Elements
In all the above examples, we have already made use of the Println() function that the fmt package provides us with. Let's explore two more such functions and we will also look at how we can print the array elements using for loop as well.
package main
import (
"fmt"
)
func main() {
arr := [...]int{1,2,3}
fmt.Println(arr)
fmt.Printf("The arr is %v\n", arr)
}
In the above example, we are printing the entire array first with the help of the Println() function and then with the help of the Printf() function. Notice that in the Printf() function, I am making use of the verb %v which stands for value. Whenever you aren't sure what type of values an array is holding, feel free to make use of the %v verb to print the values of the array.
[1 2 3]
The arr is [1 2 3]
Example: Printing Arrays Elements using loop
In case, we want to print the arrays using the for loop construct, we have three possible scenarios, one is where we simply make use of the standard for loop which includes initialization and incrementation along with evaluation, the second approach is to make use of a for loop that acts like a while loop and the last approach are to make use of the range clause.
It should also be noted that we can also make use of the reflect package's function called ValueOf that also prints all the values that are present in the array.
All these three approaches are shown in the example below.
package main
import (
"fmt"
"reflect"
)
func main() {
arr := [...]int{1, 2, 3}
for i := 0; i < len(arr); i++ {
fmt.Print(arr[i], " ")
}
fmt.Println()
var index int
for index < len(arr) {
fmt.Print(arr[index], " ")
index++
}
fmt.Println()
for _, val := range arr {
fmt.Print(val , " ")
}
fmt.Println(reflect.ValueOf(arr))
}
1 2 3
1 2 3
1 2 3
1 2 3
Reflect Package TypeOf() and Kind() on Arrays
Sometimes it is very useful to know what kind of values are present in the array and what is the exact type of the current array that we are dealing with. Along with the type of the array, we can also infer whether whatever data structure we are dealing with is actually an array or not.
Both the approaches of inferring the type and the actual structure value using the Kind() function are shown below.
package main
import (
"fmt"
"reflect"
)
func main() {
arr := [...]int{1, 2, 3}
fmt.Println(reflect.TypeOf(arr))
fmt.Println(reflect.ValueOf(arr))
fmt.Println(reflect.ValueOf(arr).Kind())
}
[3]int
[1 2 3]
array
Arrays are value type
In Go, whenever we assign an array to a new variable then instead of actually passing the address of the array, we are simply passing a copy of that array, and hence if we make any changes to the new array then that won't affect the previous(or main) array at all.
Consider the example shown below that depicts this case, where we have an array named nums1 which contains 6 integer values, and then simply assign that array to a new variable followed by making changes in the new array.
package main
import (
"fmt"
)
func main() {
nums1 := [...]int{1, 2, 3, 4, 5, 6}
nums2 := nums1
nums2[0] = 100
fmt.Println(nums1)
fmt.Println(nums2)
}
[1 2 3 4 5 6]
[100 2 3 4 5 6]
Filtering Array Values
In Go, we can extract values from the array based on indexes and this is what is sometimes known as filtering array values. The idea is that we make use of a starting index and(or) an ending index, where we can either omit one of these indexes or both the indexes.
If we have both the starting index and the ending index separated by a colon, then we will get all the values from the starting index(including) to the ending index(excluding).
In case, we have either of these, then we have two cases, the first one is where we only have the starting index, and no ending index, in that case, we will get all the elements from the starting index(including) to the last element of the array, the second case is where we only have the ending index, and no starting index, in that case, we will get all the elements from the starting element of the array to the ending index(excluding), and the last case is simple, where we don't have both the starting and the ending index, in that case, we will get the entire array itself.
It should also be noted that whenever we filter the array values, we will get a slice in return and we can also confirm that by using the TypeOf() function of the reflect package.
Example: Filter Array Elements
Consider the example shown below that depicts all the cases mentioned above.
package main
import (
"fmt"
"reflect"
)
func main() {
nums1 := [...]int{1, 2, 3, 4, 5, 6}
nums2 := nums1[:2]
nums3 := nums1[1:3]
nums4 := nums1[2:]
nums5 := nums1[:]
fmt.Println(nums1, reflect.TypeOf(nums1))
fmt.Println(nums2, reflect.TypeOf(nums2))
fmt.Println(nums3, reflect.TypeOf(nums3))
fmt.Println(nums4, reflect.TypeOf(nums4))
fmt.Println(nums5, reflect.TypeOf(nums5))
}
[1 2 3 4 5 6] [6]int
[1 2] []int
[2 3] []int
[3 4 5 6] []int
[1 2 3 4 5 6] []int
Multi-Dimensional Arrays
We can also create multi-dimensional arrays in Go. The syntax for declaring a multidimensional array is shown below.
[len1][len2].....[lenN] T {}
Where len1, len2,..., lenN are length of each of the dimensions and T is the data type.
It should be noted that all the rules that apply to the one-dimensional array will also apply to the multidimensional array as well. It is also possible to specify the array elements during the declaration. In case, the array elements are not specified during declaration, then all the array elements are allocated the default zero value of the <data_type>.
Example: Creating and Accessing Multidimensional Array
Consider the example shown below where we are declaring a two-dimensional array with the help of array literals.
package main
import (
"fmt"
)
func main() {
twoDArray := [2][3]int{{1, 2, 3}, {4, 5, 6}}
fmt.Println("Rows in twoDArray are:", len(twoDArray))
fmt.Println("Columns in twoDArray are:", len(twoDArray[0]))
fmt.Println("Total elements in twoDArray are:", len(twoDArray)*len(twoDArray[0]))
// Traversing the array
for _, row := range twoDArray {
for _, val := range row {
fmt.Print(val," ")
}
}
}
Rows in twoDArray are: 2
Columns in twoDArray are: 3
Total elements in twoDArray are: 6
1 2 3 4 5 6
One of the key points to note about arrays is that you cannot use a negative index. If you do this with a constant or a literal index, it is a compile-time error.
Example: Invalid Array Index
Consider the example shown below, where we are trying to access an element at an index that is not present in the array at all.
package main
import (
"fmt"
)
func main() {
twoDArray := [2][3]int{{1, 2, 3}, {4, 5, 6}}
fmt.Println(twoDArray[1][4])
}
./prog.go:10:26: invalid array index 4 (out of bounds for 3-element array)
Conclusion
In this article, we covered a wide variety of examples of arrays and learned about the different approaches of declaring arrays along with what should be avoided when printing the arrays or accessing a specific index. We also learned about multi-dimensional arrays as well.