DEV Community

Cover image for Go Beginners Series: Collection Types, Arrays, Slices, and Maps
Adams Adebayo
Adams Adebayo

Posted on • Originally published at olodocoder.hashnode.dev

Go Beginners Series: Collection Types, Arrays, Slices, and Maps

In the previous parts of this series, you have learned about variables and how they help you store a specific value for easy use later in your code. You also learned about the different data types in Go and how to use them to better represent information in your code. However, there are cases when these won't be sufficient regarding related data and other scenarios.

In this article, we will explore what data structures are in Go and how to use arrays, slices, and maps to work with related data in your Go applications.

Collection Types

Collection types in Go are used to store related data in a single unit for easy access and utilization. They enable you to group and access related data in your applications efficiently and fast.

Collection types in Go are a different approach to data structures, providing three different collection types arrays, slices, and maps. We will explore what these are in the following sections.

Arrays

Go allows you to store values of the same type in a collection called arrays. You can create an array in Go with a square bracket containing the length of the array followed by the data type of the values and, finally, the values of the array inside a pair of curly braces:

var classesOfFood = [6]string{"Carbohydrates", "Proteins", "Fats and Oils", "Vitamins", "Minerals", "Water"}
Enter fullscreen mode Exit fullscreen mode

The code above defines an array, classesOfFood which contains six string values.

Accessing Array Values

You can access the values of an array with the index and square bracket notation like this:

 fmt.Println(classesOfFood[0]) // Carbohydrates
 fmt.Println(classesOfFood[1]) // Proteins
Enter fullscreen mode Exit fullscreen mode

The code above will print the first and second values of the classesOfFood array. The index starts from 0.

The range Keyword

Go allows you to loop through arrays with the for loop and the range keyword like this:

 for index, value := range classesOfFood {
  fmt.Println(index, value)
 }
Enter fullscreen mode Exit fullscreen mode

The code above looped through the classesOfFood array and printed out the index and value of each element:

0 Carbohydrates
1 Proteins
2 Fats and Oils
3 Vitamins
4 Minerals
5 Water
Enter fullscreen mode Exit fullscreen mode

If you do not need the index or the value of the values, you can discard them with the blank identifier (_) like this:

 for _, value := range classesOfFood {
  fmt.Println(value)
 }
Enter fullscreen mode Exit fullscreen mode

The code above will return only the values in the array.

Array Comparison

Go allows you to compare arrays with the == and != operators. For example, if you want to check whether two different arrays are of same length and contain the same values, you can do that like this:

var typesOfFood = [...]string{"Fruits", "Vegetables", "Grains", "Meats", "Dairy", "Sweets"}

var compare = classesOfFood == typesOfFood // false
Enter fullscreen mode Exit fullscreen mode

The code above defines an array, typesOfFood, and a compare variable, which checks if both arrays are equal and stores the value. The compare variable will return false because even though the length of the arrays is the same, they hold different values.

Note: The array's length can be omitted by replacing it with three dots ... as in the above code block. The compiler will infer the length based on the number of values inside the curly braces.

Multidimensional Arrays

A multidimensional array is an array that contains other arrays. You can create a multidimensional array in Go like this:

var alphs = [2][3]string{{"a", "b", "c"}, {"d", "e", "f"}}
Enter fullscreen mode Exit fullscreen mode

The code above defined a multidimensional array, alphs. The first square bracket is the length of the outer array, and the second square bracket is the length of the inner arrays. You can loop through a multidimensional array in Go like this:

 for index, value := range multidimensionalArray {
  fmt.Println(index, value)
 }
Enter fullscreen mode Exit fullscreen mode

The code above will return:

0 [a b c]
1 [d e f]
Enter fullscreen mode Exit fullscreen mode

However, if you want to print out all the values inside the arrays, you can use a nested for loop like this:

 for i := 0; i < len(multidimensionalArray); i++ {
  for j := 0; j < len(multidimensionalArray[i]); j++ {
   fmt.Println(multidimensionalArray[i][j])
  }
 }
Enter fullscreen mode Exit fullscreen mode

The code above will return:

a
b
c
d
e
f
Enter fullscreen mode Exit fullscreen mode

Slices

Go allows you to store an array of values that you would like to add to and delete later in a collection called a slice, a dynamically-sized reference type built on top of an array. Unlike an array, a slice does not have a fixed length.

Just like an array, you can define a slice in Go like this:

var todos = []string{"Learn Go", "Learn Python", "Learn JavaScript"}
Enter fullscreen mode Exit fullscreen mode

The only difference is that there's no length or ... in the definition of a slice.

The make Function

You can also define a slice using the make function like this:

var groceriesList = make([]string, 10, 20)
Enter fullscreen mode Exit fullscreen mode

The code above defined a slice with the make function. The first number is the length of the slice, and the second number is the array's capacity, which is the number of values the slice can contain before being resized.

Accessing Slice Values

Just like arrays, you can access the values of a slice with the index and square bracket notation:

 fmt.Println(todos[0]) // Learn Go
 fmt.Println(todos[1]) // Learn Python
Enter fullscreen mode Exit fullscreen mode

The code above will print the first and second values of the todos array. The index starts from 0.

Adding Items to a Slice

Go allows you to add items to a slice with the append slice. For example, to add new items to the todo slice, you can do that like this:

 todos = append(todos, "Learn C++")
Enter fullscreen mode Exit fullscreen mode

That code above will add the new item to the end of the slice, and the todos slice will now look like this:

 [Learn Go Learn Python Learn JavaScript Learn C++]
Enter fullscreen mode Exit fullscreen mode

Looping through Slices

You can loop through a slice in Go the same way you do with arrays using the for loop and the range keyword:

 for _, todos := range todos {
  fmt.Println(todos)
 }
Enter fullscreen mode Exit fullscreen mode

The code above looped through the todos slice and will print out the following result:

Learn Go 
Learn Python 
Learn JavaScript 
Learn C++
Enter fullscreen mode Exit fullscreen mode

Slicing a Slice

You can extract a slice from another slice in Go with a method called slicing. For example, if you want to remove the first three items from the todo slice:

newSlice := todos[0:3]
fmt.Println(newSlice)
Enter fullscreen mode Exit fullscreen mode

The code above will return:

 [Learn Go Learn Python Learn JavaScript]
Enter fullscreen mode Exit fullscreen mode

You can omit the first number if you are starting from the first item like this:

newSlice := todos[:3]
fmt.Println(newSlice)
Enter fullscreen mode Exit fullscreen mode

If you want to create a new slice that starts from the second item to the end, you can do that like this:

newSlice := todos[1:]
fmt.Println(newSlice)
Enter fullscreen mode Exit fullscreen mode

The code above will return:

[Learn Python Learn JavaScript Learn C++]
Enter fullscreen mode Exit fullscreen mode

You can copy all the items inside the todos slice into the newSlice slice by omitting both numbers like this:

newSlice := todos[:]
fmt.Println(newSlice)
Enter fullscreen mode Exit fullscreen mode

The code above will return:

[Learn Go Learn Python Learn JavaScript Learn C++]
Enter fullscreen mode Exit fullscreen mode

Removing Items from a Slice

There is no in-built function for removing items from a slice in Go. However, you can create a function that does that for you like so:

func removeTodos(slice []string, elem string) []string {
 // Create a new slice to store the result
 newSlice := make([]string, 0, len(slice))
 // Loop over the elements in the original slice
 for _, value := range slice {
  // If the element is not the one to remove, add it to the new slice
  if value != elem {
   newSlice = append(newSlice, value)
  }
 }
 return newSlice
}
Enter fullscreen mode Exit fullscreen mode

The code above defines a function, removeTodos that takes in a slice and the value that should be removed from the slice and can be used like this:

fmt.Println(removeTodos(todos, "Learn Go"))
Enter fullscreen mode Exit fullscreen mode

The code above will remove the value "Learn Go" from the todos slice.

Note: the removeTodos function will remove all the occurrences of the value "Learn Go" if it appears multiple times in the slice.

Copying Slices

You can also create a copy of a slice in Go with the copy method like so:

 todosCopy := make([]string, len(todos))

 copy(todosCopy, todos)

 fmt.Println(todosCopy)
Enter fullscreen mode Exit fullscreen mode

The code above created a todosCopy slice using the make function and the same length as the todos slice, then prints out the todosCopy slice. The code above will return the values of the todos slice as it was when it was declared like so:

[Learn Go Learn Python Learn JavaScript]
Enter fullscreen mode Exit fullscreen mode

Now that you understand how to use arrays and slices in Go let's explore the significant differences between them so you can make an informed decision on when to use either of them in your code.

Differences between Arrays and Slices in Go

Arrays and slices are fundamental data types in Go, but they have major differences.

  1. Fixed-size vs. dynamic size: Arrays have a fixed size determined at compile time, whereas slices have a dynamic size that can be changed at runtime.

  2. Value type vs. reference type: Arrays are value types, which means that when you assign an array to a new variable or pass it as a parameter to a function, a copy of the array is created. On the other hand, Slices are reference types, which means that when you assign a slice to a new variable or pass it as a parameter to a function, a reference to the underlying array is created.

  3. Length vs. capacity: Arrays have a fixed length determined at compile time, whereas slices have a dynamic length that can be changed at runtime. Slices also have a capacity, which is the maximum length of the slice before it needs to be resized.

In general, slices are more flexible and powerful than arrays in Go since they allow you to work with dynamic sequences of elements. However, arrays can be helpful when a fixed-size data structure is required.

Let's explore maps and how to use them in the next section.

Maps

Go allows you to define collections of key-value pairs using a map. A map is a collection of key-value pairs where each key is unique and associated with a value. Maps are declared using the "map" keyword, followed by the key and value types in square brackets. For example:

var userIds = map[int]string{2901: "Sally", 2902: "Adeoye", 2903: "Obalola"}
Enter fullscreen mode Exit fullscreen mode

The code above defines a userIds map with integer keys, string values, and three initial items. You can also create an empty map using the following:

var foodCodes map[string]int // empty map with the map keyword

var dressCodes = make(map[string]int) // empty map with the make function
Enter fullscreen mode Exit fullscreen mode

Looping Through a Map

You can loop through a map in Go using the for loop and the range keyword like this:

 for key, value := range userIds {
  fmt.Println(key, value)
 }
Enter fullscreen mode Exit fullscreen mode

The code above loops through the userIds map and prints out all the keys and values:

2901 Sally
2902 Adeoye
2903 Obalola
Enter fullscreen mode Exit fullscreen mode

Note: The iteration order over the key-value pairs in a map can vary between program runs.

Adding Items to Maps

You can add items to a map by assigning values to new keys like this:

 userIds[2904] = "Oluwaseun"
 userIds[2905] = "Oladapo"
 fmt.Println(userIds) 
Enter fullscreen mode Exit fullscreen mode

The code above will return:

map[2901:Sally 2902:Adeoye 2903:Obalola 2904:Oluwaseun 2905:Oladapo]
Enter fullscreen mode Exit fullscreen mode

Checking the Size of a Map

You can check the size of a map with the len function like this:

 fmt.Println(len(userIds)) // prints 5
Enter fullscreen mode Exit fullscreen mode

The code above will return the number of key-value pairs in the userIds map.

Deleting Items from a Map

You can delete items from a map with the delete keyword like this:

delete(userIds, "2904")
Enter fullscreen mode Exit fullscreen mode

The code above will delete the item with the 2904 key from the map.

Deleting Multiple Items from a Map

There's no in-built function for deleting multiple items from a map in Go. However, you can create a function that does that with a loop like this:

func deleteMultipleItems(m map[int]string, keys ...int) {
 for _, key := range keys {
  delete(m, key)
 }
}
Enter fullscreen mode Exit fullscreen mode

The code above defines a deleteMultipleItems function that takes in the map and multiple keys and removes the items associated with the keys from the map. You can use the deleteMultipleItems function with the userIds map like so:

 deleteMultipleItems(userIds, 2901, 2902, 2903)
 fmt.Println(userIds)
Enter fullscreen mode Exit fullscreen mode

The code above will return:

map[2904:Oluwaseun 2905:Oladapo]
Enter fullscreen mode Exit fullscreen mode

Checking If an Item Exists in a Map

It's a good practice to always check if an item exists in a map before adding or deleting it. You can check if an item already exists in a map using the if conditional statement and the ok keyword like this:

 if _, ok := userIds[2901]; ok {
  fmt.Println("Key exists")
 } else {
  fmt.Println("Key does not exist")
 }
Enter fullscreen mode Exit fullscreen mode

The code above will return "Key exists", if the key is found and "Key does not exist" if the given key is not in the map.

Conclusion

Arrays, slices, and maps are powerful tools that allow you to store and manipulate data differently, depending on your application needs. Understanding the differences between these collection types and when to use them can help developers write more efficient and readable code. I hope this article achieved its aim of teaching you all you need to know about collection types in Go and how to use them in your code.

In the next part of the series, we will explore what pointers and structs are in Go and how to use them.

Please leave your feedback, corrections, questions, and suggestions in the comment section, and I'll reply to all of them. Thanks!

Top comments (2)

Collapse
 
monfernape profile image
Usman Khalil

Hi, I'm a bit unclear on make function.

Collapse
 
olodocoder profile image
Adams Adebayo

Hey Usman,

The make function is used to create and initialize maps, slices, and channels in Go.

They’re mostly used when you want to define the size of the data structure upon creation.