Significance of Go — Part 4 (Arrays, Slices, Maps and Structs)

Wasura Wattearachchi
7 min readJul 5, 2020

In the previous article, we learned about variables, pointers and constants/iota in Go. In this section, I will introduce the four of the collections in Go which are arrays, slices, maps and structs.

Arrays

In this section, I am going to show you the similarity/difference between the arrays and the slices in Go.

An array can be defined as a collection of the same data types. In Go, arrays can be defined in two ways as shown in the below table. To learn more about arrays refer here.

There are some special things that you can notice when working with Go arrays.

If you have not initialized an array the default values will be zeros.

Consider the below screenshot with its outputs.

Default values are initialized as zero values

In Go, if an array is not initialized with values, it will be initialized with the zero value for the corresponding data type according to the length of the array.

Also, you can find the length of an array by len() function as shown below.

Finding the length of an array

Use […] instead of length if the length of the array should be decided by the number of elements in the array automatically.

Please find the below screenshot and check the output you got.

Use […] when declaring the array

As you can see, the length of the array was not specified in line 10, instead, we have used ellipses as inside square brackets […]. When you check the length of the array in line 10, you can see that it is 4 because there are only 4 elements that have been assigned to the array in line 10.

Can compare two arrays using == operator.

As shown in the below screenshot when you compare two arrays, if they are similar the output will be true, else false.

Comparing two arrays

But here the type of the above arrays are similar, which is [4]int. Instead, if you try to compare an array with type [3]int with an array of type [4]int, this will not give you false, but will give you an error as shown below.

Error when you try to compare different type of arrays

Slices

Since array has a fixed length, there is a need for another collection type which can be dynamic in size. This is the place where a slice comes into action.

A slice on top of an array

A slice can be defined on top of an array if you like. Consider the below code segment and its output.

A slice on top of an array

Here, the slice is defined using the array with 4 elements. (In line 10, when we were defining the slice, we have used “:” inside arr1 to denote that, indexes from 0 to end of arr1 should be considered when creating the slice.)

Now, let’s see another interesting thing. Change the code as follows and notice the output.

Relationship between the slice and the array

What we have done here is,

  • In line 12, we have changed the first element of arr1 to 100.
  • In line 13, we have changed the last element of slice to 200.

As you can see, in the output, both these changes have been reflected in both the array and the slice. The reason for this is,

The slice is pointing to the data that is inside the array. You can see a slice as a kind of a pointer which points to the corresponding array. Any change that you have done to the slice will be reflected in the array and vice versa.

In here we, since we are defining the slice on top of an array, it is cumbersome. Ultimately, we have bound to a fixed-sized array when defining the slice which is not the real expectation of a slice. As the solution, you should follow an approach as discussed in the next section, by defining a slice without an underline array.

A slice without an explicit underline array

Refer to the below screenshot to learn how to define a slice without an explicitly defined underline array.

A slice without an explicit underline array

Here, in line 8, the slice was defined without specifying the size inside square brackets. (Note that, do not use ellipses inside square brackets like […], then you will be defining an array not a slice.)

The compiler has created an underlying array here, not us. That array is not visible to us. The compiler has created it, and along with that, it has created a slice which is pointing to that array. That slice is the only thing that we can access here.

If a slice is a pointer to a fixed sized array defined by the compiler, how can we say that a slice is dynamic?

To illustrate that I will use the below screenshot.

append function with slices

In line 12, we have used the append() function to append the elements 100 and 200 to the slice named “slice”. Here, what happened was, the compiler has created a new array with the elements of the current underlying array (which is with 1, 2, 3 and 4) and has added the new elements to the end of the new array, and has changed the reference of “slice” variable to that newly created array. This is how the dynamic behaviour of a slice is incorporated.

Maps

A map is a collection of key-value pairs. It will map each of the values with the corresponding key so that the user can access the values using the keys as shown in the below screenshot.

Define a map and access the values

Note that, similar to arrays and slices, in maps too, you can have only one single data type. The above map named “ages”, consists of keys which are strings that map to integer values. Here, you can only use strings as keys and integers as values, nothing else. To learn more about maps, refer here.

Structs

Arrays, slices, and maps do not have the ability to associate discrete data types together. A struct is the only collection type that has this ability. A struct can be defined as follows.

type book struct {
Title string
Sold bool
Pages int
}

Here the name of the struct is “book”, which associates 3 different data types into one collection. The values can be initialized to this struct in three ways as shown below.

Three ways to initialize a struct

Here, the lines 14 to 18 represent the 1st Method, lines 20 to 21 represents the 2nd Method and lines 23 to 27 represents the 3rd Method. The commonly used methods are 2nd and 3rd where 3rd is more read-friendly than the 2nd one.

Do you notice that there is comma in line 25 after 233? What happens if you remove that comma?

If you remember in the 1st article we discussed that the Go compiler will automatically insert semicolons at the end of each line and the problems associated with it. Same thing will happen here, if you do not use the comma in line 25. When you insert the comma here, you will not get any error. (Just try removing the comma and check what type of an error that you will get)

Conclusion

In this article, we discussed arrays, slices, maps and structs in Go. Further, we identified how a slice is different from the traditional data type array and the characteristics of those. Also, we learned the uniqueness of a struct that has the ability to associate different data types together. To learn more about arrays and slices please refer to the below link.

Let’s meet next time with another article on Go. Goodbye till then!

Previous Articles

--

--