Golang: Slice

By Xah Lee. Date: . Last updated: .

What is Slice

Slice is like Array but length can be changed. (Golang slice is essentially a reference to a segment of array. )

Syntax of Slice Type

[]type
Syntax for slice type, with each slot of type type. [see Golang: Basic Types]
Example: var x []int, declare a variable x of int slice type.
package main

import "fmt"

func main() {

	// declare var of type slice
	var ss []int

	// print the type
	fmt.Printf("%T", ss) // []int

}

Literal Expression of Slice

[]type{v1, v2 }
Create a slice with values. Example: var ss = []int{9, 2, 6}
package main

import "fmt"

func main() {

	// slice
	var ss = []int{9, 2, 6}

	fmt.Printf("%v\n", ss) // [9 2 6]
	fmt.Printf("%T\n", ss) // []int

}

Print Slice

Create slice with “make”

You can create a slice with make. It lets you specify how many items to begin with, and capacity for growth.

make([]type, n)
Create a slice of n number of slots of type type, with default values of nil. [see Golang: Zero Value] n can be 0.
make([]type, n, capacity)
With capacity of capacity number of slots. capacity defaults to the value of n.
Example: make([]int, 10, 1000)
Note: capacity is not necessary, because golang automatically grow the slice capacity when you append() beyond the capacity. However, capacity is there for efficiency reasons, because creating a new array with lots items is relatively slow. Best to always create a slice with expected max of items.
package main

import "fmt"

func main() {

	// 3 slots of int
	var s = make([]int, 3)
	fmt.Println(s) // [0 0 0]

	// 3 slots of int, capacity of 9
	var s2 = make([]int, 3, 9)
	fmt.Println(s2) // [0 0 0]
}

Length

len(s)
Return the length of slice s.

Capacity

cap(s)
Return the capacity.

Slice of Slice

s[a:b]
Return a slice of s from index a to b. The a is included, The b is excluded. The result shares the same data with original. If you modify it, the original will also be modified.
s[:n]
Same as s[0:n]
s[n:]
Same as s[n:len(s)]
package main

import "fmt"

func main() {
	var s = []int{0, 1, 2, 3}

	// take a slice of values
	var x = s[1:3]

	fmt.Println(x) // [1 2]
}

Here's a example where modifying the slice also modifies the original.

package main

import "fmt"

func main() {
	var s = []int{0, 1, 2, 3}

	// take a slice
	var x = s[1:3]

	// modify it
	x[0] = 99

	// original also changed
	fmt.Printf("%v\n", s)
	// [0 99 2 3]

}

Append to Slice

The append is a critical function in golang. It's used to append, prepend, join, slices, or delete elements in slice. You need to pay attention whether it returns a new slice or just modify the original.

append(slice_x, new_item1, new_item2 )
Append new items to a slice, returns a new slice only if the result is more than the original slice's capacity.
(WARNING: if the original slice is a slice of slice, then result may not go beyond its capacity, therefore, the result is modified original slice. Meaning, change to the result also changes original slice.)
package main

import "fmt"

func main() {

	var s1 = []int{3, 5}
	var s2 = append(s1, 8, 9)

	fmt.Println(s2) // [3 5 8 9]

	// original not changed, in this case
	fmt.Println(s1) // [3 5]

}

Append creates a new slice ONLY WHEN the result is beyond original capacity.

package main

import "fmt"

func main() {

	var x1 = []int{0, 1, 2, 3, 4, 5}
	var x2 = x1[:3] // [0 1 2]

	var x3 = append(x2, 22)

	fmt.Println(x3) // [0 1 2 22]

	// x1 is changed
	fmt.Println(x1) // [0 1 2 22 4 5]

	// --------------------------------------------------
	// if the append added more items than the capacity of x1, then x1 will not be changed
	// now we do the above again to see

	var y1 = []int{0, 1, 2, 3, 4, 5}
	var y2 = y1[:3] // [0 1 2]

	var y3 = append(y2, 21, 22, 23, 24, 25)

	fmt.Println(y3) // [0 1 2 21 22 23 24 25]

	// y1 is not changed
	fmt.Println(y1) // [0 1 2 3 4 5]

}

Join Slices

Use triple dots operator to turn a slice into function arguments, then use append.

append(slice_x, slice_y ...)

package main

import "fmt"

func main() {

	var s1 = []int{3, 5}
	var s2 = []int{6, 7}
	var s3 = append(s1, s2...)

	fmt.Println(s3) // [3 5 6 7]

}

Append String as Byte Slice to Slice

Use triple dots operator to turn a string into byte slice, then use append.

append(slice_x, string ...)

Cut Slice (Delete Elements)

Use append to delete elements, like this:

append(s[:i], s[j:]...)
Delete from index i to j.
package main

import "fmt"

func main() {

	var x = []byte("0123456")

	x = append(x[:3], x[5:]...)

	fmt.Printf("%s\n", x)
	// 1236

}

Copy Slice

copy(dst, src)
Copy elements of slice from src to dst. The number of elements copied is the smaller of lengths of argument, whichever is shorter. It wipes the values in the dst slice starting at index 0. Return the number of items copied.
Arguments must be slice of the same type.
In the case of byte slice, the src can be a string too.
package main

import "fmt"

func main() {
	var x = []int{0, 1, 2, 3, 4, 5}
	var y = []int{99, 999}
	copy(y, x)
	fmt.Println(y) // [0 1]
}

Example of copying shorter to longer:

package main

import "fmt"

func main() {
	var x = []int{99, 999}
	var y = []int{0, 1, 2, 3, 4, 5}
	copy(y, x)
	fmt.Println(y) // [99 999 2 3 4 5]
}

Clear Slice

To clear slice, set it to nil or set it to a slice of 0 length.

mySlice = nil

or

mySlice = mySlice[0:0]

The recommended way is to set to nil.

Nested Slice

Slices can be nested. Just declare that the slots are also type slice.

var x [][]int
Declare a nested slice of int type.
package main

import "fmt"

func main() {
	var x [][]int
	fmt.Println(x) // []
}

Nested Slice with Values

var y = [][]int{{3, 4}, {7}, {1, 2}}
Declare nested slice, with initial values.
package main

import "fmt"

func main() {
	// y is slice of slice of int
	var y = [][]int{{3, 4}, {7, 8, 9}, {1, 2}}
	fmt.Println(y) // [[3 4] [7 8 9] [1 2]]
}

Create Nested Slice with make

var ns = make([][]string, 2)
Create a nested slice.
package main

import "fmt"

func main() {

	// nested slice. 2 items. each item is a slice of string
	var ns = make([][]string, 2)

	// fill the slots
	ns[0] = []string{"a", "b"}
	ns[1] = []string{"x", "y", "z"}

	fmt.Println(ns) // [[a b] [x y z]]
}

Getting and setting values.

package main

import "fmt"

func main() {

	var ss = make([][]int, 2)

	ss[0] = []int{1, 2}
	ss[1] = []int{3, 4}

	ss[1][1] = 5

	fmt.Println(ss) // [[1 2] [3 5]]
}

Slice of Strings to String

strings.Join(slice, seperator)
Join a Slice of Strings to one big string.
package main

import "fmt"
import "strings"

// join slice of strings to one big string

func main() {
	var sls = []string{"abc", "xyz"}
	var result = strings.Join(sls, ",")
	fmt.Printf("%v\n", result)
	// abc,xyz
}

Loop Thru Slice

for i, v := range slice {}
Loop thru slice, where i is current index and v the value. If a variable is not used, name it _ to stop compiler from complaining. Example: for _, v := range slice {}
The _ is called blank identifier.
package main

import "fmt"

func main() {
	var s = []int{9, 2, 8, 61}
	for i, x := range s {
		fmt.Println(i, x)
	}
}

// 0 9
// 1 2
// 2 8
// 3 61