Golang Tutorials - Beginner guide Slice Examples

This blog post covers Golang Slice Complete tutorials with example

Golang Slice Introduction

Arrays are a static fixed size. Slices are dynamically sized, It means arrays once created can not change their size. Slices can change the size and

It gives more power and flexibility compared with Arrays.

I already posted an article on Arrays in Golang.

Key points of Slice.

  • Slice is a dynamic array that can increase its size
  • Slices are similar to Arrays in other programming language-go
  • Slice does not contain its data and uses internal an array
  • Internally Slices uses Array point as a reference to it, has more power, and is flexible
  • Slices elements are indexable

Slice Variable Create and Initialize

There are many ways we can create a Slice variable and initialize it

Slice Empty Values

An empty slice can be created with empty data assigned to it. This is used to represent empty collections like no results found for database queries

emptySlice:= []int{} // variable value is []

Here variable is declared with initialized with empty values. The internal array is created Empty Slice returns zero for len() and cap() functions.

Here is a complete example of Slice Empty with zero values.

package main

import (
 "fmt"
)

func main() {
 var emptySlice = []int{}
 fmt.Println(emptySlice, emptySlice == nil, len(emptySlice), cap(emptySlice))

}

The output of the above program is

[] false 0 0

Nil Slice non-zero values

The Nil slice is created using empty length and type. A slice created with the value not initialized is also called slice nil.

Here internal array is not created.

This will be used to represent a slice that does not exist inside a function call.

var variable []int  //// variable value is nil

The Nil slice always returns zero for length and capacity

Here is a complete example of Slice Nil with zero values

package main

import (
 "fmt"
)

func main() {
 var nilSlice []int
 fmt.Println(nilSlice, nilSlice == nil, len(nilSlice), cap(nilSlice))

}

The output of the above program is

[] true 0 0

Create and initialize Slice using literal

This is one of the ways of creating a slice with literal syntax. Here is the syntax of a slice literal

// Slice Creation using slice literal
var strs = []string{"one", "two", "three"}
fmt.Println(strs) //[one two three]

Here we create slice strings using slice literals syntax.

The right-hand side contains Slice literals. Literal is an expression, each of which specifies a slice element, enclosed in brackets []. When a variable is declared, Internally, a variable is created and assigned with these values. Here length is empty, the compiler infers the length from many elements of the slice.

The above slice literal is rewritten using shorthand variable declaration syntax

strs := []string{"one", "two", "three"}

Here short assignment operator -:= is used by omitting the var keyword.

Following is an example of using slice literals creation

package main

import (
 "fmt"
)
func main() {
 // Slice Creation using slice literal
 var strs = []string{"one", "two", "three"}
 fmt.Println(strs)
 // Slice Creation using shorthand variable declaration
 strs1 := []string{"one", "two", "three"}
 fmt.Println(strs1)
}

Output is

[one two three]
[one two three]

Create a slice from an array - of low and high expression

Slice can be created using a segment of an array. Slice is created with low and high indexes separated by a colon. Here is a syntax

k[low:high]

Slice k is created using an array specifying low and high separated with a colon symbol. low specifies the starting index of a slice, and high is the end index of a slice . ie length of an array -1 for example

array := [5]int{1,2,3,4,5}
s1:= array[0:5] //  [1,2,3,4,5]

The above line creates a slice from an array. The slice contains all the values of an array starting from low=0 to high=len() -1.

s2:= array[1:3] //  [2,3]

low and high indexes are optional. default values of low are always zero and high is the length of an array -1 The same can be rewritten by omitting low and high indexes

array[0:] same as  array[0:len(array)]
array[:5] same as  array[0:5]
array[:] same as  array[0:len(array)]

Following is a complete example creation of a slice from an array

package main

import (
 "fmt"
)

func main() {
 array := [6]int{1, 2, 3, 4, 5, 6} // array creation
 s1 := array[1:5] // Slice creation from array
 s2 := array[:2] // Slice creation from array
 s3 := array[1:] // Slice creation from array
 s4 := array[:] // Slice creation from array
 fmt.Println("oringal array: ", array)
 fmt.Println("s1 = ", s1)
 fmt.Println("s2 = ", s2)
 fmt.Println("s3 = ", s3)
 fmt.Println("s4 = ", s4)

}

Output is

oringal array:  [1 2 3 4 5 6]
s1 =  [2 3 4 5]
s2 =  [1 2]
s3 =  [2 3 4 5 6]
s4 =  [1 2 3 4 5 6]

Slice creation using other Slice

This is another way of creating a slice from the existing slice. This will be useful when you want to create a part of a slice and assign it to another slice

package main

import (
 "fmt"
)

func main() {
 originalSlice := []string{"one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"}

 copySlice1 := originalSlice[2:]
 copySlice2 := copySlice1[1:3]
 copySlice3 := originalSlice[:]
 copySlice4 := originalSlice[:4]

 fmt.Println("originalSlice : ", originalSlice)
 fmt.Println("copySlice1 : ", copySlice1)
 fmt.Println("copySlice2 : ", copySlice2)
 fmt.Println("copySlice3 : ", copySlice3)
 fmt.Println("copySlice4 : ", copySlice4)
}

The output of the above program is

originalSlice :  [one two three four five six seven eight nine ten]
copySlice1 :  [three four five six seven eight nine ten]
copySlice2 :  [four five]
copySlice3 :  [one two three four five six seven eight nine ten]
copySlice4 :  [one two three four]

Create a slice using make() function

Slice can be created using the in-built make() function. Here is the syntax of make() function

func make([]T, len, cap) []T

This accepts the datatype array, length, and capacity creates an array internally, and returns a slice that references an internal array. Capacity is optional. Based on the first type of the argument, non-zero values are printed (for numeric - 0, String -space) for example

slice1 := make([]int, 4)
fmt.Printf("length=%d capacity=%d slice=%v\n",len(slice1), cap(slice1), slice1) // length=4 capacity=4 slice=[0 0 0 0]

This creates a slice with array integer non-zero values, length=4 and capacity=4 when capacity is not specified and the default is equal to length The capacity is supplied, the Underlying array is created with capacity 6, and data is stored up to length =3

slice2 := make([]int, 3, 6)
fmt.Printf("length=%d capacity=%d slice=%v\n",len(slice2), cap(slice2), slice2) //length=3 capacity=6 slice=[0 0 0]

A complete example of slice make a function

package main

import (
 "fmt"
)

func main() {
 slice1 := make([]int, 4)
 fmt.Printf("length=%d capacity=%d slice=%v\n",
  len(slice1), cap(slice1), slice1)
 slice2 := make([]int, 3, 6)
 fmt.Printf("length=%d capacity=%d slice=%v\n",
  len(slice2), cap(slice2), slice2)
 slice3 := slice2[:2]
 fmt.Printf("length=%d capacity=%d slice=%v\n",
  len(slice3), cap(slice3), slice3)

}

Output is

length=4 capacity=4 slice=[0 0 0 0]
length=3 capacity=6 slice=[0 0 0]
length=2 capacity=6 slice=[0 0]

Length and capacity slice - len() capacity() function

Golang has built-in functions like len() and capacity() functions Slice does not hold its data, It is a reference or pointer to an underlying internal array. Len() function- length is the number of elements in a slice cap function - capacity is the number of elements in the underlying array which counts from the starting index

package main

import (
 "fmt"
)

func main() {
 // Slice Creation using slice literal
 var strs = [8]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}

 s1 := strs[1:3]
 displaySlice(s1)

}

func displaySlice(s []string) {
 fmt.Printf("  %v length:%d capacity:%d\n", s, len(s), cap(s))
}

Output is

[two three] length:2 capacity:7

The slice length can be extended by reducing its length. if it extended more than the existing capacity, It throws a runtime exception following is an example of extending/reslice example by changing its length



package main

import (
 "fmt"
)

func main() {
 // Slice Creation using slice literal
 var strs = []string{"one", "two", "three", "four", "five", "six", "seven", "eight"}
 displaySlice(strs)

 // Empty Slice
 s1 := strs[:0]
 displaySlice(s1)

 // Shirnk slice length.
 s2 := strs[:4]
 displaySlice(s2)

 // Remove first three values
 s3 := strs[3:]
 displaySlice(s3)
}

func displaySlice(s []string) {
 fmt.Printf("%v length:%d capacity:%d\n", s, len(s), cap(s))
}

Output is

[one two three four five six seven eight] length:8 capacity:8
[] length:0 capacity:8
[one two three four] length:4 capacity:8
[four five six seven eight] length:5 capacity:5

Iteration of elements in the slice

Like Array, Elements are iterated using for loop and for with range keyword

Iterate elements in a slice - for loop

This iteration works like an array as many iterations are executed over the length of the slice.

package main

import (
 "fmt"
)

func main() {
 numbs := []string{"one", "two", "three", "four"}
 for i := 0; i < len(numbs); i++ {
  fmt.Println(numbs[i])
 }
}

output is

one
two
three
four

Iteration of the element in slice using for loop with range keyword

With a range for loop, Each iteration returns two elements, the first element is an index, and the second is the actual element value if a slice is nil, zero returns are evaluated.

package main

import (
 "fmt"
)

func main() {
 numbs := []string{"one", "two", "three", "four"}
 for index, numb := range numbs {
  fmt.Printf("%d = %s\n", index+1, numb)
 }
}

Output is

1 = one
2 = two
3 = three
4 = four

You can omit either index or value in for range loop using a blank identifier Each iteration has an index and value, if you don’t want one of these, you can replace it with a blank identifier (_). The compiler treats that this value is not required The same can be rewritten with a blank identifier as

func main() {
 numbs := []string{"six", "seven", "eight", "nine"}
 for _, numb := range numbs {
  fmt.Printf("%s\n", numb)
 }
}

Output is

six
seven
eight
nine

Copy function - Copy elements in a slice

copy() is an inbuilt function of slice, copies elements from one slice to another slice

func copy(destination, source []T) int

This function has two arguments of type slice all of the source elements are copied to destination elements if elements already exist, overwrites the elements. It returns the number of elements copied i.e. minimum of len(source) and len(destination). destination slice should have sufficient capacity to copy its elements

Copy slice to another slice

This copies the src and destination slices and returns the destination slice

package main

import "fmt"

func main() {
 destination := make([]string, 4)
 source := []string{"one", "two", "three", "four"}
 fmt.Println("source: ", source)
 fmt.Println("Destination: ", destination)
 output := copy(destination, source)
 fmt.Println("Number of elements copied = ", output)
 fmt.Println("Output of Copy  = ", destination)

}

Output is

source:  [one two three four]
Destination:  [   ]
Number of elements copied =  4
Output of Copy  =  [one two three four]

Copy string bytes to byte slice example

The slice copy function can also be used to copy string bytes to a slice of bytes

package main

import "fmt"

func main() {

 var destination = make([]byte, 5)
 source := "Test string"

 fmt.Println("source: ", source)
 fmt.Println("destination: ", destination)
 output := copy(destination, source)

 fmt.Println("Number of elements copied = ", output)
 fmt.Println("Output of Copy  = ", destination)

}

Output is

source:  Test string
destination:  [0 0 0 0 0]
Number of elements copied =  5
Output of Copy  =  [84 101 115 116 32]

Append function - add an element to the end element of Slice

Slice is the dynamic size and changes its length at runtime. The append function is an inbuilt function in Slice that adds the element end of the slice. Here is a signature of the Append function

func append(inputslice []T, args ...T) []T

This function takes input slice elements args …T - This is a variadic function that contains multiple arguments and returns a new slice of all elements including existing elements. if there is enough capacity available in the underline array, the element is added end of the last element, and the length is incremented. if there is not enough capacity available, a new array will be created, all the existing values are copied to the new array, and new elements are added at the end of existing elements, a new array is referenced by the slice and returned.

package main

import "fmt"

func main() {
 numbs := []string{"one", "two", "three", "four"}

 output := append(numbs, "five", "six", "seven")
 fmt.Printf(" %v, length = %d, capacity = %d\n", numbs, len(numbs), cap(numbs))
 fmt.Printf(" %v, length = %d, capacity = %d\n", output, len(output), cap(output))
 numbs[0] = "newone"
 numbs[1] = "newtwo"
 fmt.Printf(" %v, length = %d, capacity = %d\n", numbs, len(numbs), cap(numbs))
 fmt.Printf(" %v, length = %d, capacity = %d\n", output, len(output), cap(output))

}


Output is

 [one two three four], length = 4, capacity = 4
 [one two three four five six seven], length = 7, capacity = 8
 [newone newtwo three four], length = 4, capacity = 4
 [one two three four five six seven], length = 7, capacity = 8

In the above example, slice numbs have a capacity of four, when you are appending more elements, it can’t grow its size.

The new underline array is created with a bigger size copies existing elements and appends new elements. The new slice has a capacity of 8. The original slice capacity is 3 only.

Append slice to another slice

once slice can be appended to another slice using three dots notation (…)operator Output of append function result is not overlapped

package main

import "fmt"

func main() {

 s1 := []string{"one", "two", "three"}
 s2 := []string{"four", "five", "six"}

 s3 := append(s1, s2...)

 fmt.Println("s1 = ", s1)
 fmt.Println("s2 = ", s2)
 fmt.Println("Output append = ", s3)

}

Output is

s1 =  [one two three]
s2 =  [four five six]
Output append =  [one two three four five six]

Append string bytes to Slice bytes

Using the append function, we can append a string to a slice of bytes.

package main

import "fmt"

func main() {

 s1 := []byte("one")
 s2 := "six"

 s3 := append(s1, s2...)

 fmt.Println("s1 = ", s1)
 fmt.Println("s2 = ", s2)
 fmt.Println("Output append = ", s3)

}

output is

s1 =  [111 110 101]
s2 =  six
Output append =  [111 110 101 115 105 120]

Modify a slice of elements in Golang

A slice is a reference to an internal array and does not have any data on its own. Any modifications were done to the slice change in an internal array.

package main

import "fmt"

func main() {
 slice := [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}
 newslice := slice[2:4]
 fmt.Println("Before Modification", slice)
 for k := range newslice {
  newslice[k]++
 }
 fmt.Println("After Modification", slice)

}

output is

Before Modification [1 2 3 4 5 6 7 8 9 0]
After Modification [1 2 4 5 5 6 7 8 9 0]

Create a slice with 10 elements, and create a new slice by copying index 2,3 from the original slice. Iterated the new slice using a range loop and incremented its original value. Observed incremented values in an Original slice

multidimensional slice - a slice of slices

Like arrays, Slices can be of multidimensional types. Normal slice elements can be of any type. Each type can contain slices also. It works like same as arrays. Following is an example of multidimensional slices.

package main

import "fmt"

func main() {
 multiSlice := [][]string{
  {"one", "two", "three"},
  {"four", "five", "six"},
  {"seven", "eight", "nine"},
  {"ten", "eleven", "Twelve"},
 }

 fmt.Println("Slice of slice  :", multiSlice)
 fmt.Println("length : ", len(multiSlice))
 fmt.Println("capacity : ", cap(multiSlice))
}

When the above program is compiled and output is as follows

Slice of slice  : [[one two three] [four five six] [seven eight nine] [ten eleven Twelve]]
length :  4
capacity :  4