Go: Arrays & Slices

Go: Arrays & Slices

ยท

9 min read

In Go language, an array is a collection of elements of the same type, stored in contiguous memory locations. The size of an array is fixed at the time of initialization and cannot be changed during program execution.

Array declaration

To declare an array in Go, we use the following syntax:

var name [size]datatype

For example, to declare an integer array of size 5:

var numbers [5]int

We can initialize the array either at the time of declaration or later by assigning values to individual elements.

Slice declaration

A slice, is a dynamically-sized, flexible view of an array in Go. It provides a more powerful interface to work with sequences of data. A slice is like a window into an underlying array, and allows you to view or modify a subset of the array's elements.

To declare a slice, we use the following syntax:

var name []datatype

For example, to declare an integer slice:

var numbers []int

We can initialize a slice using a slice literal. The syntax for a slice literal is similar to an array literal, but without a predefined size. For example:

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

Init Slice from Array

We can also create a slice from an existing array or another slice using the slice operator [:]. For example:

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

In this example, slice is a slice of the array containing elements from index 1 up to (but not including) index 3.

In summary, arrays in Go are fixed-size collections of elements of the same type, while slices are dynamic views of arrays with a flexible size.slices allow for more flexible and powerful handling of sequential data as compared to arrays.


Explaing Slicing

Here are several slicing secrets in Go:

  1. Slicing doesn't copy the underlying array: In Go, a slice is just a reference to an underlying array. When we slice a slice, we are creating a new slice header that points to the same underlying array. Therefore, any changes made to the sliced slice will reflect in the original slice and the underlying array.

  2. By default, a slice starts from the beginning of an array and extends to its end: When we don't provide a starting index, Go assumes it to be 0, and when we don't provide an ending index, Go assumes it to be the length of the underlying array.

  3. A slice can be extended by using the "append" function: We can use the "append" function to add new elements to the end of the slice. The new elements are appended to the same underlying array, and the slice header is updated to include the new elements.

  4. We can reverse a slice by swapping its elements: To reverse a slice, we can use a simple swapping technique, where we swap the first and last elements of the slice, and continue swapping inward.

  5. A slice can be sliced again, but only within its length and capacity: When we slice a slice, the new slice must be within the bounds of the original sliceย™s length and capacity. If we try to slice beyond the capacity of the slice, it will result in a runtime panic.

Example:

Here is a code example that demonstrates some of these secrets:

package main

import "fmt"

func main() {
    // Creating a slice
    numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    fmt.Println("Original Slice: ", numbers)

    // Slicing the slice to remove the first two elements
    numbers = numbers[2:]
    fmt.Println("After Slicing: ", numbers)

    // Appending new elements to the slice
    numbers = append(numbers, 11, 12, 13)
    fmt.Println("After Appending: ", numbers)

    // Reversing the slice
    for i := 0; i < len(numbers)/2; i++ {
        j := len(numbers) - i - 1
        numbers[i], numbers[j] = numbers[j], numbers[i]
    }
    fmt.Println("After Reversing: ", numbers)

    // Slicing the slice again
    subSlice := numbers[2:5]
    fmt.Println("Sub-slice: ", subSlice)
}

Output:

Original Slice:  [1 2 3 4 5 6 7 8 9 10]
After Slicing:  [3 4 5 6 7 8 9 10]
After Appending:  [3 4 5 6 7 8 9 10 11 12 13]
After Reversing:  [13 12 11 10 9 8 7 6 5 4 3]
Sub-slice:  [11 10 9]

Array vs Slice

In table below er explain the properties of slices and arrays in Go language through a table:

PropertiesArraysSlices
Declarationvar name [size]typevar name []type
SizeFixed, defined at initializationDynamic, can be changed during program execution
Accessing Elementsname[index]name[index] (similar to arrays)
Initializationvar name = [size]type{comma-separated values}var name = []type{comma-separated values} or make([]type, size)
CopyingNew memory is allocated and all elements are copiedNo new memory is allocated, the slice header is updated and both slices share the same underlying array
AppendingNot possible, unless the array size is changedappend() function is used to add elements to a slice
LengthAccessible using len() functionAccessible using len() function
CapacityEqual to the size of the underlying arrayCapacity can be different from the size of the underlying array

In summary, arrays are fixed-size collections of elements of the same type, while slices are dynamic views of arrays with a flexible size. Slices are more flexible than arrays, but accessing elements in a slice is similar to accessing elements in an array. Slices allow for efficient memory management and easy manipulation of sequential data in Go.


Multi-dimensional Arrays

A multidimensional array in Go is an array that contains other arrays. This means, each element of the main array is itself an array, making it a multi-dimensional structure, unlike a flat one-dimensional array where every element is a scalar value.

In Go, we can create multidimensional arrays by defining an array of arrays. For example, if we want to create a two-dimensional array with three rows and four columns, we can define it like this:

var arr [3][4]int

This creates an array with three elements of type [4]int, making it a two-dimensional array. We can access individual elements of this array with the help of two indices, the first index representing the row number, and the second index representing the column number. For example, to access the element in the first row and second column, we can use:

arr[0][1] = 5

Here, we access the value in the first row (index 0) and the second column (index 1) and assign it the value 5.

We can also initialize a multidimensional array during the declaration, like this:

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

This creates a three-row four-column array and initializes it with the values specified in the curly brackets.

Multidimensional arrays can be useful for representing data structures like matrices, tables, and grids where each element of the array represents a corresponding value in the real-world data structure. They can also be used for implementing algorithms that involve matrices and other multi-dimensional data structures.

Multi-dimensional Slice

In Go, we can also create multidimensional slices, which are more flexible and powerful than multidimensional arrays. A slice is a dynamic, resizable, and variable-length container that can store elements of the same type. Unlike arrays, slices are created without specifying their length, making them more suitable for dynamic programming needs.

We can create a multidimensional slice in Go by defining a slice of slices of the same type. For example, the following code creates a two-dimensional slice of integers with three rows and four columns:

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

for i := 0; i < 3; i++ {
    slice[i] = make([]int, 4)
}

Here, we create a slice of []int slices with a length of 3 rows, and then we allocate each of the slice with a length of 4 columns. We can access an individual element of this slice with two indices, just like a multidimensional array, by using square brackets.

For example, to access the element in the second row and the third column, we can use:

slice[1][2] = 5

This accesses the second element in the first dimension (index 1), which is a slice of []int. The second index (index 2) represents the element in this slice, and sets it to the value 5.

We can also initialize a multidimensional slice during the declaration, like this:

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

This creates a three-row four-column slice and initializes it with the values specified in the curly brackets.

Multidimensional slices are useful in situations where the size of the data structure is not known beforehand or needs to be changed dynamically. They can also be used for implementing algorithms such as graphs and trees, where nodes can have multiple child nodes.


Use-Cases:

A slice is a powerful data structure in Go that holds a sequence of elements, referred to as elements of the slice or slice elements. It uses a reference to an underlying array and has a dynamic size, which means that we can change the size of the slice and add or remove elements from it. Here are some use-cases and benefits of using slices in Go:

  1. Dynamic collection of elements: Slices provide a dynamic data structure to hold elements that can be modified at runtime. Unlike arrays with fixed lengths, slices can grow or shrink in size, which makes it an ideal choice for applications that need to store a dynamic number of elements.

  2. Effectively works with functions that require variable-length arguments: Go functions support variable-length arguments, which could be slices. This allows us to work with functions that require variable-length arguments to take slices. For example, the fmt.Print() and fmt.Println() functions work with variable-length arguments and can take slices as their argument list.

  3. Efficient for sorting and searching: Since a slice is a contiguous block of memory, it is better suited for sorting and searching operations. Go has a sort package that provides efficient in-place sorting algorithms. We can sort a slice using built-in sort package of Go that sorts a slice in-place by modifying the original slice.

  4. Concurrent data sharing among goroutines: Go supports the concept of concurrency through goroutines, and many goroutines can share data via a slice, thus making it an excellent solution for concurrent programming.

  5. Efficient for passing data between functions: Since a slice is just a reference to an underlying array, it is lightweight in nature hence ideal for passing large amounts of data to functions by reference rather than having to copy the data every time.

  6. Used in IO operations: Many IO operations in Go take a slice as their input parameter. For example, the Read() method of the io.Reader interface takes a slice of bytes, and Write() method of the io.Writer interface can take a slice.

Overall, the usability of slices is vast and has many use cases in Go. They are essential in Go programming and have become a default way of storing and manipulating collections of data, be it files, databases or network connections, among other things.


Conclusion:

Now you know what is an Array and what is a Slice. Later we will learn loops and then we will be able to explain how we can rad elements of an array one by one.


Disclaim: This article was generated using ChatGPT. I do not deserve any credit. I'm just asking the questions and do the copy pase operation. Sometimes I fix the title and sometimes are duplicates or errors that I need to eliminate. Report errors that I have not found in comments so that I can fix them.


Thanks for reading. Learn and prosper ๐Ÿ––๐Ÿผ๐Ÿ€

ย