Collections
Make
The make
keyword is used to create slices, maps, and channels that are initialized and ready for use. For example, a slice is a three component object with a pointer to an array, a length, and a capacity. Until these are set, the slice is considered nil. The make
keyword initialized these variables and makes the slice ready to use. It also returns value of type T instead of a pointer with new
.
Arrays
Arrays in Go are fixed length and must be declared at initialization.
var a [10]int
a[0] = 1
Slices
A slice is like an array but it does not have a fixed size. You can further slice a slice be specifying a low and high index, inclusive of the first and exclusive of the last.
primes := [6]int{2, 3, 5, 7, 11, 13}
var s []int = primes[1:4]
fmt.Println(s) // 3 5 7
s = primes[3:] // 7, 11, 13
s = primes[:2] // 2, 3
Slices are references to an underlying array, so if you create a slice of an array and edit that slice, you will also edit the underlying array.
names := [4]string{
"John",
"Paul",
"George",
"Ringo",
}
fmt.Println(names) // John Paul George Ringo
a := names[0:2]
b := names[1:3]
fmt.Println(a, b) // John Paul, Paul George
b[0] = "XXX"
fmt.Println(a, b) // John XXX, XXX George
fmt.Println(names) // John XXX George Ringo
Length vs Capacity
The length of a slice is how many items are actually stored in the array, and the capacity is how many slots the array has. A slice is considered a nil slice if it has 0 length and capacity and no underlying array.
package main
import "fmt"
func main() {
s := []int{2, 3, 5, 7, 11, 13}
printSlice(s)
// Slice the slice to give it zero length.
s = s[:0]
printSlice(s)
// Extend its length.
s = s[:4]
printSlice(s)
// Drop its first two values.
s = s[2:]
printSlice(s)
}
func printSlice(s []int) {
fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
// Output
// len=6 cap=6 [2 3 5 7 11 13]
// len=0 cap=6 []
// len=4 cap=6 [2 3 5 7]
// len=2 cap=4 [5 7]
You can create slices with specific length and capacity using make
.
x := make([]int, 0, 5) // len(x)=0, cap(x)=5
x = x[:cap(x)] // len(x)=5, cap(x)=5
x = x[1:] // len(x)=4, cap(x)=4
a := make([]int, 5)
// a len=5 cap=5 [0 0 0 0 0]
b := make([]int, 0, 5)
// b len=0 cap=5 []
c := b[:2]
// c len=2 cap=5 [0 0]
d := c[2:5]
// d len=3 cap=3 [0 0 0]
Appending
If the underlying array of the slice is too small to accommodate the new elements, the returned slice will point to a newly allocated array.
var s []int
// len=0 cap=0 []
// append works on nil slices.
s = append(s, 0)
// len=1 cap=1 [0]
// The slice grows as needed.
s = append(s, 1)
// len=2 cap=2 [0 1]
// We can add more than one element at a time.
s = append(s, 2, 3, 4)
// len=5 cap=6 [0 1 2 3 4]
Maps
Maps are key-value pairs. They can be created with make
.
package main
import "fmt"
type Vertex struct {
Lat, Long float64
}
var m map[string]Vertex // cannot be used
func main() {
m = make(map[string]Vertex) // now can be used
m["Bell Labs"] = Vertex{
40.68433, -74.39967,
}
fmt.Println(m["Bell Labs"])
// Map literal
var n = map[string]Vertex{
"Bell Labs": Vertex{
40.68433, -74.39967,
},
"Google": Vertex{
37.42202, -122.08408,
},
}
// Shorthand
var o = map[string]Vertex{
"Bell Labs": {40.68433, -74.39967},
"Google": {37.42202, -122.08408},
}
}
Manipulating the map
m[key] = elem
elem = m[key]
delete(m, key)
// Check if element exists
elem, ok = m[key]