Go Part 6: Arrays And Slices in Go Language

GO PART 6: ARRAYS AND SLICES IN GO


Please Subscribe Youtube| Like Facebook | Follow Twitter

Arrays And Slices In Go

In this article, we will provide a detailed overview of Arrays And Slices in Go and provide examples of how they are used in Go programming.

Arrays

  • Arrays in Go are fixed-size collections of elements of the same type.
  • The size of an array is determined at compile-time and cannot be changed.
  • Array elements are accessed using zero-based indices.
  • Arrays are value types, meaning when assigned to a new variable or passed as a function argument, a copy of the array is made.

Slices

  • Slices are more flexible than arrays and represent dynamic arrays in Go.
  • A slice is a reference to a contiguous section of an underlying array.
  • Slices have a dynamic length that can be changed using built-in functions like append() and copy().
  • Slice elements are accessed using zero-based indices, similar to arrays.
  • When a slice is assigned to a new variable or passed as a function argument, it references the same underlying array.

Arrays

Lets first discuss Arrays in Go

Syntax of Array in Go

To declare an array in Go, you need to specify the type of elements it will hold and the number of elements it can store. The syntax for declaring an array is as follows:

var arrayName [size]dataType

Here, arrayName is the name you choose for your array, size represents the number of elements it can hold, and dataType is the type of elements the array will store. For instance, to declare an integer array of size 5, you would write:

var numbers [5]int

Initializing Arrays

Go provides several ways to initialize arrays. The most common approach is to specify the initial values within curly braces {} while declaring the array. For example:

var fruits = [3]string{"Apple", "Banana", "Orange"}

In this example, we declared and initialized an array called fruits with three elements of type string.In this example, we declared and initialized an array called fruits with three elements of type string.

Accessing Array Elements

To access individual elements in an array, you can use the index number enclosed in square brackets []. The index starts from 0 and goes up to size-1. For instance, to access the second element of the fruits array, you would write:

secondFruit := fruits[1] // "Banana"

Updating Array Elements

In addition to accessing array elements, you can also update the values of specific elements in an array. To update an element, you simply assign a new value to the desired index.

To update the first element of the fruits array, you would do the following:

fruits[0] = "Mango"
//After updating the first element to "Mango", the array will look like this:

//["Mango", "Banana", "Orange"]

Iterating Over Arrays in Go

Iterating over an array involves accessing each element of the array one by one. Go provides different approaches to iterate over arrays, such as using a traditional for loop, a range loop, or the range loop with index.

Approach 1: Using a Traditional for Loop

One way to iterate over the fruits array is by using a traditional for loop with an index variable. Here’s an example:

var fruits = [3]string{"Apple", "Banana", "Orange"}

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

Output

Apple
Banana
Orange

This loop iterates from 0 to len(fruits)-1, and at each iteration, it prints the corresponding element of the fruits array.

Approach 2: Using the range Loop

The range loop is a simpler and more concise way to iterate over an array in Go. It provides both the index and value of each element. Here’s an example:

for _, fruit := range fruits {
fmt.Println(fruit)
}

Output

Apple
Banana
Orange

In this loop, the underscore _ is used to discard the index value since we’re not using it. The loop iterates over each element of the fruits array and assigns it to the variable fruit. Then, it prints the value of fruit in each iteration.

Approach 3: Using the range Loop with Index

If you need to access both the index and value of each element in the array, you can modify the previous example as follows:

for i, fruit := range fruits {
    fmt.Printf("Index: %d, Fruit: %s\n", i, fruit)
}

Output

Index: 0, Fruit: Apple
Index: 1, Fruit: Banana
Index: 2, Fruit: Orange

This loop iterates over the fruits array, assigning the index to i and the value to fruit. It then prints both the index and value in each iteration. The output will be:

Sorting Arrays in Go:

Sorting arrays allows you to arrange the elements in a specific order, such as ascending or descending. Go provides a built-in package called sort that offers various sorting algorithms to sort arrays conveniently.

To demonstrate array sorting, let’s consider an example with an integer array called numbers:

var numbers = [6]int{9, 4, 7, 2, 5, 1}

Sorting in Ascending Order

To sort the numbers array in ascending order, you can use the sort.Ints() function from the sort package. Here’s an example:

import "sort"

sort.Ints(numbers[:])

fmt.Println(numbers) // Output: [1 2 4 5 7 9]

Output

[1 2 4 5 7 9]

In this code, we import the sort package and then call the Ints() function, passing numbers[:] as the argument. The [:] notation creates a slice that references the entire array. After sorting the array using Ints(), we print the sorted numbers array, which will be in ascending order.

Multidimensional Arrays in Go

A multidimensional array is an array of arrays. Go also supports multidimensional arrays, allowing you to create arrays with more than one dimension. To declare a multidimensional array, you can use the following syntax:

var matrix [3][3]int

In this example, we created a 3×3 matrix with integer elements. You can access individual elements using multiple indices, like matrix[rowIndex][columnIndex].

Initializing a 2D Array

To initialize a 2D array, you can use the following syntax:

var matrix [3][3]int = [3][3]int{
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9},
}

In this code, we declare a 2D array called matrix with a size of 3 rows and 3 columns. Each element in the array is initialized with specific values using the nested curly braces.

Accessing Elements of a 2D Array

To access elements in the matrix array, you need to specify the row and column indices using square brackets. Here are a few examples:

element := matrix[1][2]

In this case, matrix[1] selects the second row, and [2] selects the third column within that row. The value of element will be 6.

To access an entire row or column, you can use the index without specifying the second index. For example:

row := matrix[1]

In this case, matrix[1] selects the second row of the matrix array. The row variable will be an array containing [4, 5, 6].

Traversing a Multidimensional Array in Go

To traverse and print the elements of a multidimensional array in the desired format, you can use loop as follows:

var matrix = [4][3]int{
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9},
    {10, 11, 12},
}

// Traversing and printing by row
for i := 0; i < len(matrix); i++ {
    for j := 0; j < len(matrix[i]); j++ {
        element := matrix[i][j]
        fmt.Printf("%d ", element)
    }
    fmt.Println()
}

Output

1 2 3
4 5 6
7 8 9
10 11 12

In this code, the inner loop prints each element element followed by a space using fmt.Printf(“%d “, element). After printing all elements in a row, fmt.Println() is used to move to the next line, creating the desired row-wise output.

Slices

Now lets discuss slices in Go

Slice Declaration

Using an existing array

You can create a slice by specifying the range of indices from an existing array. This creates a slice that references a section of the underlying array.

The syntax is sliceName := arrayName[startIndex:endIndex]. It creates a slice that references a section of the underlying array, including elements from startIndex up to, but not including, endIndex.

array := [5]int{1, 2, 3, 4, 5}
slice := array[1:4]

In this example, slice is a slice created from the array containing elements from index 1 up to, but not including, index 4.

Using the make() function

The make() function is used to create a slice with a specified length and capacity. This allocates an underlying array and creates a slice based on it.

slice := make([]int, 3, 5)

This creates a slice named slice with a length of 3 and a capacity of 5.

Short declaration

You can declare and initialize a slice directly using the short declaration syntax.

slice := []int{1, 2, 3}

This creates a slice named slice with elements 1, 2, and 3.

Accessing Slice Elements

You can access individual elements of a slice using the index notation.

fmt.Println(slice[0]) // Output: 1

Modifying Slice

Appending elements

To add elements to a slice, you can use the append() function.

slice = append(slice, 4, 5)

This appends elements 4 and 5 to the end of the slice.

Slicing

You can create a new slice from an existing slice using slicing.

newSlice := slice[1:3]

This creates a new slice named newSlice that contains elements from index 1 up to, but not including, index 3 of the original slice.

Modifying a specific element

You can modify a specific element of a slice by assigning a new value to the corresponding index.

slice[0] = 10

This changes the value of the first element of the slice to 10.

Length and Capacity

Length: The length of a slice can be obtained using the len() function.

fmt.Println(len(slice)) // Output: 5

This prints the number of elements in the slice.

Capacity: The capacity of a slice represents the maximum number of elements it can hold without allocating a new underlying array. The capacity can be obtained using the cap() function.

fmt.Println(cap(slice)) // Output: 8

This prints the capacity of the slice.

Iterate over a slice in Go

Here’s an example of how to iterate over a slice in Go

package main

import "fmt"

func main() {
    slice := []string{"Apple", "Banana", "Orange"}

    // Method 1: Using a for loop with range
    for index, value := range slice {
        fmt.Printf("Index: %d, Value: %s\n", index, value)
    }

    // Method 2: Using a for loop with indexing
    for i := 0; i < len(slice); i++ {
        fmt.Printf("Index: %d, Value: %s\n", i, slice[i])
    }
}

Output

Index: 0, Value: Apple
Index: 1, Value: Banana
Index: 2, Value: Orange
Index: 0, Value: Apple
Index: 1, Value: Banana
Index: 2, Value: Orange

In this example, we have a slice slice containing three elements: “Apple”, “Banana”, and “Orange”. We iterate over the slice using two different methods:

Method 1: Using a for loop with range. The range keyword returns both the index and value of each element in the slice. We use the index and value variables to access and print the index and value of each element.

Method 2: Using a for loop with indexing. We initialize a loop counter i to 0 and iterate until i reaches the length of the slice. Inside the loop, we access and print the index and value of each element using the loop counter i.

Both methods will produce the same output, which displays the index and value of each element in the slice.

Differences between arrays and slices in Go

Here’s a table highlighting the key differences between arrays and slices in Go

ArraysSlices
Fixed size, determined at compile-timeDynamic size, can be modified
Elements are stored sequentially in contiguous memoryElements are stored as references to an underlying array
Length is fixed and cannot be changedLength can be modified by appending or removing elements
Declared using square brackets with a specific sizeDeclared using square brackets with no size or using make() function
Values are copied when assigned or passed to a functionSlice header is copied, underlying array is shared
Limited functionality and built-in operationsAdditional functions like append() and copy() available
Better performance and memory efficiency for fixed-size collectionsFlexibility to modify length and add/remove elements

Best practices for working with arrays and slices in Go:

  1. Use slices when flexibility is needed: Slices provide dynamic sizing and convenient built-in functions, such as append() and copy(), making them more versatile than arrays. Use slices when you need to modify the length or add/remove elements.
  2. Prefer slices over arrays: Slices are commonly used in Go due to their flexibility. Unless you have a specific requirement for a fixed-size collection, it’s usually more convenient to work with slices.
  3. Initialize slices with make(): When creating a slice with a specific length and capacity, use the make() function. It ensures that the underlying array is properly allocated, and the length and capacity are set correctly.
  4. Use the range keyword for iteration: The range keyword provides a concise and efficient way to iterate over arrays and slices. It returns both the index and value of each element, simplifying the iteration process.
  5. Be mindful of underlying array modifications: Remember that slices are references to underlying arrays. Modifying the underlying array affects all slices referencing it. If you need independent copies, use the copy() function to create a new slice with a separate underlying array.
  6. Avoid unnecessary copying: When passing slices to functions or assigning them to new variables, keep in mind that a copy of the slice header is made. It doesn’t duplicate the underlying array. Only make copies when necessary to optimize memory usage.
  7. Use array when size is fixed and known: If you have a fixed-size collection with a known size, use an array. Arrays have a fixed size determined at compile-time, which can provide better performance and memory efficiency.

Example code with output:

package main

import "fmt"

func main() {
	// Use slices when flexibility is needed
	slice := []int{1, 2, 3}
	slice = append(slice, 4) // Adding element to the slice
	fmt.Println("Slice:", slice)

	// Prefer slices over arrays
	preferredSlice := []string{"Apple", "Banana", "Orange"}
	fmt.Println("Preferred Slice:", preferredSlice)

	// Initialize slices with make()
	makeSlice := make([]int, 5, 10)
	fmt.Println("Make Slice:", makeSlice)
	
	// Use the range keyword for iteration
	for index, value := range slice {
		fmt.Printf("Index: %d, Value: %d\n", index, value)
	}
	
	// Be mindful of underlying array modifications
	modifySlice(slice)
	fmt.Println("Modified Slice:", slice)
	
	// Avoid unnecessary copying
	newSlice := make([]int, len(slice))
	copy(newSlice, slice) // Creating an independent copy of the slice
	fmt.Println("New Slice:", newSlice)
	
	// Use array when size is fixed and known
	array := [3]int{1, 2, 3}
	fmt.Println("Array:", array)
}

func modifySlice(slice []int) {
	slice[0] = 10
}

Output

Slice: [1 2 3 4]
Preferred Slice: [Apple Banana Orange]
Make Slice: [0 0 0 0 0]
Index: 0, Value: 1
Index: 1, Value: 2
Index: 2, Value: 3
Modified Slice: [10 2 3 4]
New Slice: [10 2 3 4]
Array: [1 2 3]

In this example:

  • The first part demonstrates using slices when flexibility is needed. The slice is dynamically sized, and we append an element to it using append().
  • The second part showcases using slices over arrays. The preferredSlice is a slice rather than an array.
  • The third part demonstrates initializing a slice with make(). The makeSlice is a slice with a length of 5 and a capacity of 10.
  • The fourth part shows using the range keyword for iteration over the slice.
  • The fifth part emphasizes being mindful of underlying array modifications by modifying the slice in a function.
  • The sixth part illustrates avoiding unnecessary copying by creating an independent copy of the slice using copy().
  • The last part highlights using an array when the size is fixed and known.

Conclusion

In conclusion, arrays and slices are fundamental data types in Go for working with collections of elements. While arrays have a fixed size determined at compile-time, slices provide dynamic sizing and additional functionality.

It’s important to choose between arrays and slices based on your specific requirements. Arrays are suitable for scenarios where a fixed-size collection is needed, providing better performance and memory efficiency. On the other hand, slices offer flexibility with dynamic sizing, convenient functions, and the ability to modify the length.

Go Beginner Tutorial Series

Please Subscribe Youtube| Like Facebook | Follow Twitter


Leave a Reply

Your email address will not be published. Required fields are marked *