Sitemap
Devpriya Shivani

Devpriya Shivani

Go Arrays

6 min readJul 7, 2024

--

Press enter or click to view image in full size
Arrays in Go

Arrays are a fundamental data structure in many programming languages, and Go is no exception. It lets you allocate a contiguous block of memory and provides a way to store multiple values of the same type in a single variable. In this blog post, we’ll explore the basics of arrays in Go, including how to declare, initialize, and manipulate them.

Declaring Arrays

In Go, you declare an array by specifying its size and the type of its elements. The syntax is as follows:

var arrayName [size]elementType

For example, to declare an array of five integers, you would write:

var numbers [5]int

This creates an array named numbers that can hold five integers.

Initializing Arrays

You can initialize an array at the time of declaration by providing a list of values:

var numbers = [5]int{1, 2, 3, 4, 5}

Alternatively, you can let Go infer the size of the array based on the number of elements you provide:

var numbers = [...]int{1, 2, 3, 4, 5}

Both of these declarations create an array of integers with the specified values.

Size is Part of the Type

In Go, the size of the array is part of its type. This means that [5]int and [6]int are different types, and you cannot assign one to the other without a compilation error.

package main

import "fmt"

func main() {
var five [5]int
four := [4]int{1, 2, 3, 4}
five = four
fmt.Println(four)
}

Output:

cannot use four (variable of type [4]int) as [5]int value in assignment

The compiler is not complaining that these 2 arrays are of different sizes, what they are complaining about is that the arrays are of different types.

Try it yourself!

func main() {
var five [5]int
newFive := [5]int{1, 2, 3, 4, 5}
five = newFive
fmt.Println(five)
}

Let us see another example:

package main

import "fmt"

func main() {
const Number = 3
var number = 4

var cars [5]string
var bikes [Number]string
var cycles [number]string

fmt.Printf("Number of Cars: %d\t Cars: %v\n", 5, cars)
fmt.Printf("Number of Bikes: %d\t Bikes: %v\n", Number, bikes)
fmt.Printf("Number of Cycles: %d\t Cycles: %v\n", number, cycles)
}

Output:

invalid array length number

Since size is part of the type, size cannot be a variable as it can be changed anywhere throughout the code.

Try it yourself!

Make number a constant variable const number = 4

Predictable Stride

It refers to the regular and consistent spacing between elements in a data structure, such as an array, when stored in memory. In the context of Go arrays:

var fruits [4]string
Press enter or click to view image in full size
  • Contiguous Memory Allocation: An array allocates a contiguous block of memory for its elements. For example, an array of four strings allocates memory for all four string headers in a single continuous block.
  • Consistent Element Spacing: Each element in the array is stored at a predictable offset from the previous element. For instance, if each string header is 16 bytes, the distance (stride) between the starting addresses of consecutive elements is 16 bytes.
  • Efficient Memory Access: This regular spacing allows the hardware to access elements efficiently. When the CPU accesses array elements, it can quickly calculate the memory address of any element using simple arithmetic, leading to faster data retrieval and manipulation.

Efficient String Handling in Go

The cost of moving a string around your program in Go is relatively non-existent. Whether the string is 5 bytes or 5 million bytes, all we have to do is copy the 16-byte header (8 bytes for the pointer and 8 bytes for the length), making string manipulation very efficient.

var fruits [4]string
fruits[0] = "APPLE"
fruits[1] = "BANANA"
fruits[2] = "ORANGE"
fruits[3] = "GRAPE"
Press enter or click to view image in full size
8 bytes for the pointer and 8 bytes for the length

The string header leverages pointer semantics to efficiently move both small and large pieces of data around your program. From a Go perspective, if you want to move a string around your program, you can simply give the function its own copy of the string. This approach maintains high levels of efficiency.

Iteration in Go: Exploring the Versatile for Keyword

When it comes to iteration in Go, the language offers a streamlined approach by utilizing a single keyword: for. This simplicity contrasts with some other languages that have separate keywords for different types of loops. In Go, for can be used in several ways, each suited to different scenarios. Let’s dive into the details.

Get Devpriya Shivani’s stories in your inbox

Join Medium for free to get updates from this writer.

Constructing Arrays and Using Literal Syntax

Consider the following example where we construct an array of four integers using literal construction syntax:

package main

import "fmt"

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

Output:

[1 2 3 4]

Here, we initialize the array with specific values instead of the default zero values. This approach is concise and clear, setting each element explicitly.

Try it yourself!

Replace arr value with the following and comment the output:
1. arr := […]int{1, 2, 3, 4}
2. arr := [4]int{0: 1, 2: 3}

The Traditional for Loop

Go’s for loop is straightforward and mirrors the traditional loops found in other languages:

package main

import "fmt"

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

for i := 0; i < len(arr); i++ {
fmt.Println(arr[i])
}
}

Output:

1
2
3
4

This loop iterates over the array, accessing each element by its index. If you’ve used for loops in other languages, this should feel familiar.

The for Loop as a while Loop

In Go, the for keyword also serves the purpose of a while loop. Here’s how it looks:

package main

import "fmt"

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

i := 0
for i < len(arr) {
fmt.Println(arr[i])
i++
}
}

Output:

1
2
3
4

This construct behaves like a while loop, continuing until the condition (i < len(arr)) is no longer met.

The for range Loop

One of the powerful features in Go is the for range loop, which simplifies iteration over collections:

package main

import "fmt"

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

for index, value := range arr {
fmt.Println(index, value)
}

fmt.Println()

for index := range arr {
fmt.Println(index, arr[index])
}
}

Output:

0 1
1 2
2 3
3 4

0 1
1 2
2 3
3 4

In this form, index represents the current index, and value is a copy of the element at that index. This loop ensures that you won't go out of bounds, iterating safely from the beginning to the end of the collection.

Value Semantics vs. Pointer Semantics

The for range loop in Go supports both value semantics and pointer semantics. Understanding when to use each is crucial.

Value Semantics

When you want to operate on copies of the data, use the following form:

package main

import "fmt"

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

for _, value := range arr {
fmt.Println(value)
}
}

Output:

1
2
3
4

Here, value is a copy of each element. This form is suitable when each iteration should work with its own copy, maintaining value semantic consistency.

Pointer Semantics

If you need to modify the original data, use this form:

package main

import "fmt"

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

fmt.Println("Initial Array: ", arr)

for index := range arr {
arr[index] *= 2
}

fmt.Println("Final Array: ", arr)
}

Output:

Initial Array:  [1 2 3 4]
Final Array: [2 4 6 8]

In this case, you access and modify the original array elements directly.

Conclusion

Arrays in Go are a powerful and flexible way to manage collections of data. From declaring and initializing arrays to iterating over them using various forms of the for loop, Go provides a robust set of tools for working with arrays. Understanding the nuances of array types, predictable stride, and efficient string handling will help you write more efficient and effective Go programs. Whether you're working with value semantics or pointer semantics, Go's array capabilities ensure you can handle data effectively, leveraging the language's strengths in performance and simplicity.

--

--