Mastering Arrays And Iteration In Go: Exploring Arrays, Loops, And Common Iteration Patterns
Overview
This chapter provides an in-depth exploration of arrays and iteration in Go. You will learn the fundamentals of arrays, including their fixed size and type, how to create and initialize them, and how Go handles array indexing. The chapter also covers common loop constructs, including for loops, range loops, and control mechanisms like continue and break. You’ll also gain hands-on experience with two-dimensional arrays, iteration patterns, and using Go’s range keyword to simplify array iteration. By the end, you’ll have a solid foundation for working with arrays and iteration in Go, setting the stage for more advanced data structures.
Arrays
Arrays are:
- Fixed length
- Fixed type
- Zero based
Initializing An Array
Array Zero Value
The zero value of each element in an array is the zero value for the type of elements in the array.
Given the following code:
package main
import "fmt"
func main() {
// section: main
names := [4]string{}
ints := [4]int{}
fmt.Printf("%q\n", names)
fmt.Println(ints)
// section: main
}
/*
// section: output
["" "" "" ""]
[0 0 0 0]
// section: output
*/Output:
Indexing Arrays
You will receive an error (either compile time or a panic) when trying to access an index of the array beyond it’s size.
names[4] = "Stu"
invalid array index 4 (out of bounds for 4-element array)
Array Type
It’s important to remember that an array can only be of the type is was declared. All of the following will result in compiler errors:
strings := [4]string{"one", "two", "three", "four"}
ints := [4]int{1, 2, 3, 4}
strings[0] = 5 // Can't put an int in a string array
ints[0] = "five" // Can't put a string in an int arraypackage main
func main() {
// section: main
strings := [4]string{"one", "two", "three", "four"}
ints := [4]int{1, 2, 3, 4}
strings[0] = 5 // Can't put an int in a string array
ints[0] = "five" // Can't put a string in an int array
// section: main
}
/*
// section: output
./main.go:7:13: cannot use 5 (type untyped int) as type string in assignment
./main.go:8:10: cannot use "five" (type untyped string) as type int in assignment
// section: output
*/Output:
./main.go:7:13: cannot use 5 (type untyped int) as type string in assignment
./main.go:8:10: cannot use "five" (type untyped string) as type int in assignmentpackage main
func main() {
// section: main
strings := [4]string{"one", "two", "three", "four"}
ints := [4]int{1, 2, 3, 4}
strings[0] = 5 // Can't put an int in a string array
ints[0] = "five" // Can't put a string in an int array
// section: main
}
/*
// section: output
./main.go:7:13: cannot use 5 (type untyped int) as type string in assignment
./main.go:8:10: cannot use "five" (type untyped string) as type int in assignment
// section: output
*/Array Type Definition
The length is actually part of the type that is defined for arrays.
package main
import "fmt"
func main() {
a1 := [2]string{"one", "two"}
a2 := [2]string{}
a2 = a1
fmt.Println(a2)
a3 := [3]string{}
// This can't be done, as it is not of the same type
//a3 = a2
fmt.Println(a3)
}Setting Array Values
It is important to note that if you create two like arrays, and then set the value of one array to the other, they still continue to have their own memory space.
func main() {
a1 := [2]string{"one", "two"}
a2 := [2]string{}
a2 = a1
fmt.Println("a1:", a1)
fmt.Println("a2:", a2)
a1[0] = "bob"
fmt.Println("a1:", a1)
fmt.Println("a2:", a2)
}
package main
import "fmt"
// section: main
func main() {
a1 := [2]string{"one", "two"}
a2 := [2]string{}
a2 = a1
fmt.Println("a1:", a1)
fmt.Println("a2:", a2)
a1[0] = "bob"
fmt.Println("a1:", a1)
fmt.Println("a2:", a2)
}
// section: main
/*
// section: output
a1: [one two]
a2: [one two]
a1: [bob two]
a2: [one two]
// section: output
*/Output:
package main
import "fmt"
// section: main
func main() {
a1 := [2]string{"one", "two"}
a2 := [2]string{}
a2 = a1
fmt.Println("a1:", a1)
fmt.Println("a2:", a2)
a1[0] = "bob"
fmt.Println("a1:", a1)
fmt.Println("a2:", a2)
}
// section: main
/*
// section: output
a1: [one two]
a2: [one two]
a1: [bob two]
a2: [one two]
// section: output
*/Two Dimensional Arrays
Go’s arrays are one-dimensional. To create an equivalent of a 2D array, it is necessary to define an array-of-arrays.
// A 3x3 array, really an array of arrays.
type Matrix [3][3]int
func main() {
m := Matrix{
{0, 0, 0},
{1, 1, 1},
{2, 2, 2},
}
fmt.Println(m)
}
The `for` Loop
In Go there is only one looping construct; the for loop.
Use it for for, while, do while, do until, etc…
for i := 0; i < N; i++ {
// do work until i equals N
}
Iterating Over Arrays
Iterating over arrays is done using a for loop.
package main
import "fmt"
func main() {
names := [4]string{"John", "Paul", "George", "Ringo"}
for i := 0; i < len(names); i++ {
fmt.Println(names[i])
}
}package main
import "fmt"
func main() {
names := [4]string{"John", "Paul", "George", "Ringo"}
for i := 0; i < len(names); i++ {
fmt.Println(names[i])
}
}The len function returns the length of the array (4).
Continuing A Loop
The continue keyword allows us to go back to the start of the loop and stop executing the rest of the code in the for block.
for {
if i == 3 {
// go to the start of the loop
continue
}
// do work
}
This does not stop the loop from executing, but rather ends that particular run of the loop.
Breaking A Loop
To stop execution of a loop we can use the break keyword.
for {
if i == 3 {
// stop looping
break
}
// do work
}
The for loop is now stopped and will no longer run.
Do While Loop
A do while loop is used in a situation where you want the loop to run at least 1 iteration, regardless of the condition.
A C/Java-style example would look something like this:
do {
task();
} while (condition);
To create a do while style loop in Go a combination of an infinite loop and the break keyword can be used:
The `range` Keyword
Previously we used a “classic” for loop to iterate over an array:
package main
import "fmt"
func main() {
names := [4]string{"John", "Paul", "George", "Ringo"}
for i := 0; i < len(names); i++ {
fmt.Println(names[i])
}
}package main
import "fmt"
func main() {
names := [4]string{"John", "Paul", "George", "Ringo"}
for i := 0; i < len(names); i++ {
fmt.Println(names[i])
}
}Looping over arrays, and other collection types, is so common that Go created the range tool to simplify this code.
package main
import "fmt"
func main() {
names := [4]string{"John", "Paul", "George", "Ringo"}
for i, n := range names {
fmt.Printf("%d - %s\n", i, n)
}
}package main
import "fmt"
func main() {
names := [4]string{"John", "Paul", "George", "Ringo"}
for i, n := range names {
fmt.Printf("%d - %s\n", i, n)
}
}Range returns the index and the value of the array.
Exercise (10m)
package main
func main() {
fruits := [4]string{"Banana", "Orange", "Pineapple", "Strawberry"}
// Use a 'classic' for loop to print out each fruit in the array, and the
// corresponding index.
// Use the range keyword to loop over the same array of fruits, again printing
// out the fruit and the corresponding index.
// Using the keyword `continue`, skip every other fruit (even ones)
// HINT: the `%` is the `mod` operator in Go
}package main
func main() {
fruits := [4]string{"Banana", "Orange", "Pineapple", "Strawberry"}
// Use a 'classic' for loop to print out each fruit in the array, and the
// corresponding index.
// Use the range keyword to loop over the same array of fruits, again printing
// out the fruit and the corresponding index.
// Using the keyword `continue`, skip every other fruit (even ones)
// HINT: the `%` is the `mod` operator in Go
}Solution
package main
import "fmt"
func main() {
fruits := [4]string{"Banana", "Orange", "Pineapple", "Strawberry"}
// Use a 'classic' for loop to print out each fruit in the array, and the
// corresponding index.
for i := 0; i < len(fruits); i++ {
fmt.Println(i, fruits[i])
}
// Use the range keyword to loop over the same array of fruits, again printing
// out the fruit and the corresponding index.
for i, f := range fruits {
fmt.Println(i, f)
}
// Using the keyword `continue`, skip every other fruit (even ones)
for i, f := range fruits {
if i%2 == 0 {
continue
}
fmt.Println(i, f)
}
}package main
import "fmt"
func main() {
fruits := [4]string{"Banana", "Orange", "Pineapple", "Strawberry"}
// Use a 'classic' for loop to print out each fruit in the array, and the
// corresponding index.
for i := 0; i < len(fruits); i++ {
fmt.Println(i, fruits[i])
}
// Use the range keyword to loop over the same array of fruits, again printing
// out the fruit and the corresponding index.
for i, f := range fruits {
fmt.Println(i, f)
}
// Using the keyword `continue`, skip every other fruit (even ones)
for i, f := range fruits {
if i%2 == 0 {
continue
}
fmt.Println(i, f)
}
}