Sunday, November 25, 2018

Learn Golang Tutorials - Beginner guide Slice Examples

This blog post covers Golang Slice Complete tutorials with example

Golang Slice Introduction

Arrays are static fixed size. Slices are dynamically sized, This means arrays once created can not change its size. Slice can change 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 own data and uses an array internally
  • Internally Slices uses Array point a reference to it,  have more power and 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

empty slice can be created with empty data assigned to it. This is used to represent empty collection like no results found for database queries
emptySlice:= []int{} // variable value is []
Here variable is declared with initialized with empty values. Here 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

Nil slice is created using empty length and type. Slice created with the value not initialized and it is called slice nil. Here internal array is not created
This will be used to represent a slice that does not exist inside a functions call.
var variable []int  //// variable value is nil
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))

}
An output of the above program is
[] true 0 0

Create and initialize Slice using literal

This is one of the way creating a slice with literal syntax Here is a syntax of 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. Right-hand side contains Slice literals. Literal is an expression, each of which specifies a slice element, enclosed in brackets []. When a variable is created literals. variable created and assigned with this values. Here length is empty, the compiler infers the length from a number of elements of the slice. The above slice literal is rewritten using shorthand variable declaration syntax
strs := []string{"one", "two", "three"}
here short assignment operator - := used by omitting var keyword.
Following is an example of using slice literals creation 
package main

import (
 "fmt"
)
func main() {
 // Slice Creaation using slice literal
 var strs = []string{"one", "two", "three"}
 fmt.Println(strs)
 // Slice Creaation 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 - 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 with specifying low and high separated with colon symbol low specifies starting index of a slice high is 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 value 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 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 slice from existing slice. This will be useful when you want to create a part of slice and assign to other 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)
}
An 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 in-built make() function Here is an syntax of make() function
func make([]T, len, cap) []T
This accepts datatype array, length, and capacity and creates array internally and return slice which references to an internal array. Capacity is optional. Based on the first type of the argument, non zero values are printed (for numeric - 0, String -empty 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 own 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 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
Slice length can be extended by reslicing it's length. if it extended more than existing capacity, It throws runtime exception following is an example for 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 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 array as a number of iterations are executed over length of 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 return two elements, the first element is an index, second is the actual element value if a slice is a 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 blank identifier each iteration has index and value, if you don't want one of this, you can replace with a blank identifier (_). Compiler treat 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 ie minimum of len(source) and len(destination). destination slice should have sufficient capacity to copy its elements

Copy slice to another slice 

This copies 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 

Slice copy function can also be used to copy string bytes to 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 end element of Slice 

Slice is the dynamic size and changes its length at runtime. Append function is an inbuilt function in Slice which adds element end of the slice. Here is a signature of Append function
func append(inputslice []T, args ...T) []T
This function takes input slice elements args ...T - this is variadic functions which contains multiple arguments and return new slice of all elements including existing elements if there enough capacity available in underline array, the element is added end of last element and length is incremented if there is not enough capacity available ,new array will be created, all the existing values are copied to new array, and new elements are added at end of existing elements, new array is referenced by 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 has a capacity of four, when you are appending more elements, it can't grow its size. The new underline array is created with bigger size and copy existing elements and append new elements New slice has a capacity of 8. original slice capacity is 3 only.

Append slice to another slice 

once slice can be appended to other 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 append function(), we can append a string to 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 elements 

Slice is a reference to an internal array and has not any data on its own. Any modifications done to slice will be changed 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, created new slice from copying indexes 2,3 from original slice Iterated new slice using range loop and incremented its original value. Observed incremented values in an Original slice

multidimensional slice - slice of slices

Like arrays, Slices can be of multidimensional types. Normal slice elements can be of any type. Each type can contains slices also. This 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 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

Related article


EmoticonEmoticon