HomeSearch

Golang Slice Examples (append, cap and make)

Use slices to store elements. Call the append, cap and make functions.
Slice. Near the lake a rainbow forms. It has the entire spectrum of light. A slice could contain just part of this spectrum—not all of it.
In Go slices have underlying arrays. A slice has no size as part of its type. And with built-in methods like cap() and append() we test and mutate slices.
Append. This example creates a slice of strings. It initially has 3 elements. We then use the append built-in to add 2 more strings to the slice.

Result: The slice contains all 5 elements. A slice is an expandable, resizable array.

Golang program that uses append on slice package main import "fmt" func main() { elements := []string{"cat", "dog", "bird"} elements = append(elements, "fish", "snake") fmt.Println(elements) } Output [cat dog bird fish snake]
Cap, capacity. A slice has an underlying array. This array has a capacity (a size). This is the number of elements that the slice can hold before being resized.

Cap: The cap() built-in tells us the internal allocation heuristics of a slice. When it runs out of room, a slice's array doubles in size.

Here: We create a slice of three elements. Its cap is 3. We then add a fourth element, and its capacity doubles to 6.

Golang program that uses cap, measures capacity of slice package main import "fmt" func main() { elements := []int{100, 200, 300} // Capacity is now 3. fmt.Println(cap(elements)) // Append another element to the slice. elements = append(elements, 400) // Capacity is now 6. // ... It has doubled. fmt.Println(cap(elements)) } Output 3 6
Len, length. The len built-in returns the element count of a slice. An empty slice has a length of 0. This is not the same as capacity—only existing elements are counted.
Golang program that uses len on slice package main import "fmt" func main() { // Create an empty slice. // ... Its length is 0. items := []string{} fmt.Println(len(items)) // Append a string and the slice now has a length of 1. items = append(items, "cat") fmt.Println(len(items)) } Output 0 1
Loop, range. With the range keyword we can loop over a slice. The value returned on each iteration is the index into the slice. We can access an element with it.range
Golang program that loops over slice package main import "fmt" func main() { animals := []string{"bird", "dog", "fish"} // Loop over the slice. for v := range animals { fmt.Println(animals[v]) } } Output bird dog fish
Loop, iteration. A three-part for-loop can be used to iterate over a slice. We start at 0 and continue while the index is less than the length of the slice (found with len).For
Golang program that uses for-loop on slice package main import "fmt" func main() { colors := []string{"blue", "yellow", "orange"} // Loop over all indexes with a three-part for-loop. for v := 0; v < len(colors); v++ { fmt.Println(colors[v]) } } Output blue yellow orange
Make. With this method we can create slices of a type and size. Internally slices must be initialized, and the make() method does this for us.

Quote: The built-in function make(T, args) serves a purpose different from new(T). It creates slices, maps, and channels only, and it returns an initialized (not zeroed) value of type T.

Effective Go: golang.org

Arguments: The first argument to make() is the type of the slice. The second argument is the length of elements. The third is the capacity.

Capacity: The capacity of a slice can be set as a performance optimization to avoid future allocations. A slice resizes automatically.

Golang program that uses make to create slice package main import "fmt" func main() { // Create a slice of 5 integers. values := make([]int, 5) // Assign some elements. values[0] = 100 values[4] = 200 // Loop over elements in slice and display them. for v := range values { fmt.Println(values[v]) } } Output 100 0 0 0 200
Slice capacity benchmark. Here we benchmark a slice that has an accurate capacity set in make(). We test it against a slice that is initially empty.

And: We add 1000 ints to the slices. We find the capacity leads to a significant performance improvement.

Thus: If you have a general idea of how many elements will be added to a slice, consider specifying a capacity in make().

Versions: The garbage collector in Go has improved since early versions, but even in Go 1.7 setting a capacity tends to be faster.

Golang program that benchmarks slice capacity package main import ( "fmt" "time" ) func main() { t0 := time.Now() // Version 1: use accurate capacity for slice. for i := 0; i < 100000; i++ { values := make([]int, 1000) for x := 0; x < 1000; x++ { values = append(values, x) } if values[0] != 0 { fmt.Println(0) } } t1 := time.Now() // Version 2: use empty slice. for i := 0; i < 100000; i++ { values := []int{} for x := 0; x < 1000; x++ { values = append(values, x) } if values[0] != 0 { fmt.Println(0) } } t2 := time.Now() // Benchmark results. fmt.Println(t1.Sub(t0)) fmt.Println(t2.Sub(t1)) } Output 8.6961039s, Capacity = 1000 9.098541 s, Capacity = 0
Copy. This built-in method receives two arguments: the destination slice and the source slice. The elements from the second arguments are copied into the first argument.

Tip: Copy will copy as many elements as it can. If the destination slice is smaller than the source, all elements will be copied that fit.

Golang program that uses copy built-in function package main import "fmt" func main() { slice1 := []int{10, 20, 30} slice2 := []int{0, 0, 0, 1000} // Display slice1 and slice2. fmt.Println(slice1) fmt.Println(slice2) // Copy elements from slice1 into slice2. copy(slice2, slice1) // Slice2 now has values from slice1. fmt.Println(slice2) } Output [10 20 30] [0 0 0 1000] [10 20 30 1000]
Byte slice. This program creates a byte slice. It uses a string to initialize the slice. It then displays the byte count (with len) and converts the bytes back into a string.Bytes
Golang program that creates byte slice package main import "fmt" func main() { values := []byte("birds") fmt.Println(values) // Display length of byte slice. fmt.Println(len(values)) // Create string copy of byte slice. copy := string(values) fmt.Println(copy) } Output [98 105 114 100 115] 5 birds
Slices within slices. A slice is versatile. Once we have a slice, we can take further slices of it (subslices). We use the slice syntax on a slice of any element type.

Here: We have an int slice. We take a subslice of the middle, end and start elements. This returns new partial slices.

Golang program that uses slices within slices package main import "fmt" func main() { value := []int{10, 20, 30, 40, 50} // Get slice of slice from index 2 to 4. // ... Last index is exclusive. partial := value[2:4] fmt.Println(partial) // Get slice from index 3 to end. partial = value[3:] fmt.Println(partial) // Get slice from start to index 3. partial = value[:3] fmt.Println(partial) } Output [30 40] [40 50] [10 20 30]
Remove element. Slices do not have good support for element removal. Elements after the removed one must be shifted forward, which is slow.

Here: We use two append calls to remove an element. The string "snake" is eliminated from the result slice.

Tip: The map has a special operator (delete) for element removal. Due to a map's design, this is also much faster to perform.

Golang program that removes element from slice at index package main import "fmt" func main() { // Example slice. animals := []string{"cat", "gopher", "snake", "bird", "dog"} // We want to remove element 2, which is snake. removeIndex := 2 // Create a new empty slice. result := []string{} // Append part before the removed element. // ... Three periods (ellipsis) are needed. result = append(result, animals[0:removeIndex]...) // Append part after the removed element. result = append(result, animals[removeIndex+1:]...) // Display results. fmt.Println(result) } Output [cat gopher bird dog]
Index out of range. A slice has a size. And if we access an element out of the range of the size, we will get a runtime error. We must first check the len of a slice.
Golang program that causes runtime error package main func main() { items := []int{10, 20, 30} // This will cause an error. items[100] = 10 } Output panic: runtime error: index out of range
Initializer, variables. Often Go slice initializers use constants like 10 and 20. But we can also use variables (of the correct type).

Here: The iteration variable i in the loop is used to create small two-element slices.

Golang program that uses initializer with variables package main import "fmt" func main() { for i := 0; i < 3; i++ { items := []int{i, i + 1} fmt.Println(items) } } Output [0 1] [1 2] [2 3]
Rune slices, strings. A string contains runes. We can get a slice of runes from a string with a conversion. We can modify the rune slice.

String: We can convert the rune slice back into a string with a built-in method. A rune is a character in the string.

Golang program that gets rune slice from string package main import "fmt" func main() { // Create a rune slice from a string. animal := "cat" slice := []rune(animal) // Modify the rune slice. slice[0] = 'm'; fmt.Println(slice) // Convert the rune slice back into a string. original := string(slice) fmt.Println(original) } Output [109 97 116] mat
Sort. To sort in Go we add the "sort" package and then call methods like "sort.Strings" and "sort.Ints." For complex things we define a sort interface.Sort
Remove duplicates. A slice may contain duplicate values. But some times in a program we want to remove these. We can use a map to eliminate duplicates.Duplicates
String slice map. Slices are separate from maps. But we can put slices (like string slices) in the values of a map and then append to those slices.Map, String Slices
Convert slice to string. With strings.Join we can convert a slice into a string. For string slices, this is easy. But for int slices, we must have some special logic.Convert Slice, String
Idiomatic Go. The term "idiomatic" refers to languages. An idiomatic usage is one that sounds natural and is easy to understand. Idiomatic Go uses slices. We emphasize them over arrays.
© 2007-2019 Sam Allen. Every person is special and unique. Send bug reports to info@dotnetperls.com.
Home
Dot Net Perls