Go collections is very easy to learn. We have arrays and its close cousin slices. Then there are maps and that’s it. You can form a set using map keys as values. We will see how to create each of these types. How can we iterate through each of those types. We will see how to add an element to an existing collection.
Arrays
We can initialize an array using either of the following
1
2
3
4
5
6
7
var array [5]string
array[0] = "a"
array[1] = "b"
array[2] = "c"
array[3] = "d"
array[3] = "e"
or
1
array := [5]string{"a", "b", "c", "d", "e"}
In the last example, we can replace the length of the array 5
with ...
which will result in automatically deducting the size from the number of elements.
We can also skip indexes. The skipped indexes will be set to the zero value of the type, in the following example an empty string. The type of the following array is [3]string
since the index ` is implicitly set to empty string.
1
a := [...]string{0:"a", 2:"b"}
We can use the traditional for loop to loop through the array
1
2
3
for i := 0; i < len(array); i++ {
fmt.Println(i, array[i])
}
of the more Go’ish alternative
1
2
3
for i, s := range array {
fmt.Println(i, s)
}
Notes
- The size of the array is part of the type. i.e. the type is
[5]int
not an array ofint
. Thus[5]int
and[3]int
are not compatible types and variable of one type can’t receive a value of the other. - Arrays are rarely used because the cases of fixed size arrays are very limited. Slices are a more powerful alternative.
Slices
A slice is a data structure packed by an array (for simplicity).
Declaring a slice:
1
var zeroSlice []int
1
slice := make([]int, 5)
1
sliceWithCapacity := make([]int, 5, 8)
The third argument in the above example is capacity. When you declare a slice it has a length but also has a capacity, which is adjacent memory locations that are not utilized. This gives the slice some of the characteristics of dynamic data structures.
1
sliceWithCapacity = append(sliceWithCapacity, 10, 20, 30, 40)
The above call appends the elements to the slice. If you are keeping count, the number of elements exceed the capacity, what the slice does is that it doubles the capacity and create a new packing array for those values. It keeps doubling until the capacity exceeds a 1000 elements and in that case, it increases the capacity by 25%.
You can take a “slice” of a slice, or in other words a subset of a slice using the syntax subSlice := slice[4:5]
. Note that those two share the same packing array. Which means changes to one, affect the other. The only thing that can prevent this ripple effect is limiting the sub-slice size to minimum, i.e. the length and capacity are equal, and then append to the sub-slice. To do that we use subSlice := slice[4:5:5]
. After the append, the packing array was copied and thus any changes to the sub-slice will not affect the source slice.
Maps
The syntax to declare a zero map is
1
map1 := make(map[string]int)
We can also initialize on declaration
1
2
3
4
map1 := map[string]int{
"Google": 4,
"LinkedIn": 5,
}
To add an item to a map we use map1["Samsung"] = 3
, to delete an item from a map delete(map1, "Samsung")
. Finding an item in a map is more interesting, as the result is two variables. The first is the zero value of the value and the second is a boolean that indicates whether or not the element was found.
1
v, found := map1["Toshiba"]
You may just use v := map1["Toshiba"]
. But, you wouldn’t know if the value was actually 0
or not found.
By convention the second result is not called found but rather ok
and we usually end up with the following pattern:
1
if n, ok := map1["Toshiba"]; !ok { ... }
Finally iterating over a map using for
1
2
3
for k, v := range map2 {
fmt.Println(k, v)
}
Sets
This is intentionally a subset of Maps. There is no sets in Go, but since map keys can’t duplicate, maps can be used to represent sets. For an example to represent a set of strings we can use map[string]bool
This is a “set of strings”
Comments powered by Disqus.