Golang: Slice

By Xah Lee. Date: . Last updated: .

Slice is like array but length can be changed.

Golang slice is essentially a reference to a segment of array.

[see Golang: Array]

Syntax of Slice Type

[]type → syntax for the type of slice with each slot of type type.

Recall, syntax of array type is: [n]type. The syntax for slice just omits the n.

Example:

[see Golang: Basic Datatypes]

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

package main

import "fmt"

func main() {

	var sl = []int{3, 4, 5}

	// print it normally
	fmt.Printf("%v\n", sl) // [3 4 5]

	// print in golang syntax
	fmt.Printf("%#v\n", sl) // []int{3, 4, 5}

}

Print Slice Line by Line

To print each member on a line, you have to write a loop.

package main

import "fmt"

func printSlice(sliceX []string) error {
	for k, v := range sliceX {
		fmt.Printf("%v %v\n", k, v)
	}
	return nil
}

// --------------------------------------------------
// test

func main() {

	var fileList = []string{
		"basics.html",
		"tag_matching.html",
		"selector_syntax.html",
		"units.html",
		"colors.html",
		"color_names.html",
		"color_opacity.html",
		"gradient.html",
		"gradient_radial.html"}

	printSlice(fileList)
}

/* 
prints

0 basics.html
1 tag_matching.html
2 selector_syntax.html
3 units.html
4 colors.html
5 color_names.html
6 color_opacity.html
7 gradient.html
8 gradient_radial.html

*/

[see Golang: loop]

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.

example:

make([]int, 10, 1000) → create a slice of int, 10 slots, but with total of 1000 slots for growth.

Note: capacity is not necessary for computation, 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 growth.

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) → returns the length of slice s.

Capacity

caps(s) → return the capacity.

Slice of Slice

Warning: the result share the data with the original slice. If you modify it, the original will also be modified.

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

To append new items:

Note the dot dot dot at the end. It turns a slice or string into items as function arguments.

Warning: append creates a new slice only when result length is greater than original slice slice_x's capacity.

Normally, append will always result a slice with capacity greater than 1st arg slice_x , therefore a new slice is created and slice_x is not modified. However, if slice_x is a slice of slice slice_w, and append result is less than capacity of slice_w, then slice_w is modified.

package main

import "fmt"

func main() {

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

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

	// original not changed
	fmt.Println(ss) // [3 5]

}

Here's a example of appending a slice.

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 does not create a new a slice when the result is within original capacity.

Example:

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]

}

Cut Slice (Delete Elements)

Use append to delete elements, like this:

s = 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

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 with 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)

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]]
}

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

Reference

The Go Programming Language Specification - The Go Programming Language#Slice_types

The Go Programming Language Specification - The Go Programming Language#Appending_and_copying_slices

If you have a question, put $5 at patreon and message me.

Golang

  1. Compile, Run
  2. Source Encoding
  3. Package, Import
  4. Comment
  5. Print
  6. String
  7. String Functions
  8. Print String
  9. String Backslash Escape
  10. Rune
  11. Variable
  12. Zero Value
  13. Constant
  14. If Then Else
  15. Switch/Case
  16. Loop
  17. Basic Types
  18. Array
  19. Slice
  20. Map
  21. Struct
  22. Function
  23. Closure
  24. Pointer
  25. String, Byte Slice, Rune Slice
  26. regexp
  27. Read File
  28. Write to File
  29. Walk Dir
  30. Check File Exist
  31. System Call
  32. Get Script Path
  33. Defer
  34. Random Number

Examples

  1. Match Any Regexp
  2. Find Replace
  3. Validate Links
  4. Generate Sitemap

Reference

  1. Go Spec