GOLang Slices Guide

Sivareddy Uppathi
5 min readFeb 9, 2021

Slices are one of the powerful and flexible concept than arrays in go-language.

It is a light weight data structure.

Slice is an abstraction over an array and overcomes limitations of arrays. Like getting a size dynamically or creating a sub-array of its own and hence much more convenient to use than traditional arrays

Slices are allow to store same type of data, you are not allowed to store different types of data elements in same slice. You can think of slice is a array list with generic in java.

The main difference between slice and array in go lang is arrays are fixed in size slice are re-sizable.

Internally, slice and an array are connected with each other, a slice is a reference to an underlying array.

You are allowed to store duplicate values in slice….

Differences Between array and slice In coding:-

Slice : slc1 := []int{1,2,3……}

Array: arr:=[5]int{1,2,3,4,5}

For array you need to mention the size if you are not mention the size then it is slice.

Different Ways To Create Slice :

slc1 := []int{58, 69, 40, 45, 11, 56, 67, 21, 65}slc2 := make([]int, 5)var slc3 []int

slc1:- Integer slice created and initialized with some values.

slc2:- we are creating the slice by using predefined make() method with size of 5. In this all slice values are initialized with zeros only, because int default value is zero.

slc3:- this the one more way to create slice with nil size. Slice size is nil.

SLICE FROM ARRAY :

Get the slice from array by adding colon between lower-bound and upper-bound. ex: [lower-bound:upper-bound] -> lower-bound included and upper-bound excluded while collecting the data from array or another slice.

arr := []int{1,2,3,4,5}var slc1 = arr[1:3] //between indexes range: [2,3]slc2 := arr[0:] //0(include) to length of array: [1,2,3,4,5]slc3 := arr[:2] //upto index 2(exclude): [1,2]slc4 := arr[:] // create entire array as slice: [1,2,3,4,5] 

SLICE FROM SLICE :

There are different ways to create slices from given slice.

Note: slice will include lower-bound exclude upper-bound. ex: arr[low:high]

orgnlSlc := []int{1,2,3,4,5}var slc1 = orgnlSlc[1:4] //between indexes range: [2,3,4]slc2 := orgnlSlc[0:] //0(include) to length of array: [1,2,3,4,5]slc3 := orgnlSlc[:4] //upto index 4(exclude): [1,2,3,4]slc4 := orgnlSlc[:] // create entire array as slice: [1,2,3,4,5]slc5 := slc3[2:4] //between indexes range: [3,4]

SLICE USING PREDEFINED MAKE FUNCTION :

slc1 := make([]int, 3, 6)

Above statement did lot of things behind the scene. First, it will create array of size 6. Second, slice array. Third, it will return the reference of the slice.

DIFFERENT WAYS TO ITERATE OVER SLICE:

// Using len function........for i := 0; i < len(originalSlice); i++ {    fmt.Println(originalSlice[i])}//Using range......for index, element := range originalSlice {fmt.Printf("Index = %d and element = %s\n", index, element)}//With out index.......for _, ele := range originalSlice {    fmt.Printf("Element = %s\n", ele)}

Note* :- slice are reference type

Example:

arr := [6]int{1, 4, 3, 5}slc := arr[0:3]
// Before modifying
fmt.Println("Original_Array: ", arr) //[1,4,3,5]
fmt.Println("Original_Slice: ", slc) //[1,4,3]
/ After modification// these changes will effect on array aswell because slice is a reference type
slc[0] = 100
slc[1] = 200
slc[2] = 300
fmt.Println("\nNew_Array: ", arr) //[100,200,300,5]
fmt.Println("New_Slice: ", slc) //[100,200,300]

COMPARE SLICES :

If you try to compare two slices with the help of == operator then it will give you an error.You can only use == operator to check the given slice is nill or not.func compareSlices(slice1, slice2 []int) {fmt.Println(slice1 == nil)// fmt.Println(slice1 == slice2)// this line gives error}//Note: If you want to compare two slices, then use range for loop to match each element or you can use DeepEqual function.

MULTI-DIMENSIONAL SLICES (2D-Slice):

// multi-dimensional slice
multiDimnsnSlc1 := [][]int{{1, 2, 3}, {4, 7, 6}, {8, 5, 9}}

If you want iterate over multi-dimensional slice you need 2 for loops. One is for outer and another one is for inner.

COPY ONE SLICE INTO ANOTHER SLICE :

There are multiple scenarios to discuss while copying the slice.

copy(destination,source) : copies from source to destination.

// Diffrent slices....
slc1 := []int{1,2,3,4,5,6}
slc2 := []int{8,9,7}
slc3 := make([]int, 3)
var slc4 []int
fmt.Println("Slice_1:", slc1) //[1,2,3,4,5,6]
fmt.Println("Slice_2:", slc2) //[8,9,7]
fmt.Println("Slice_3:", slc3) //[0,0,0,0]
fmt.Println("Slice_4:", slc4) //[]
copy1 := copy(slc4, slc1)
fmt.Println("No of elements copied into Slice_4 : ", copy1)//0
//nothing is coppied because slc4 is nill
fmt.Println("Slice_4 after copy: ", slc4)
copy2 := copy(slc3, slc1)
fmt.Println("No of elements copied into Slice_3 : ", copy2) //3
fmt.Println("Slice_3 after copy: ", slc3) //[1,2,3,4]
copy3 := copy(slc2, slc1)
fmt.Println("No of elements copied into Slice_2 : ", copy3) //3
fmt.Println("Slice_2 after copy: ", slc2) //[1,2,3]

Note*: If you copy the values into existing slice all existed values are overridden by new values, which are coming from another slice.

SLICE OF SLICES :

Slice of slices means similar to 2D-arrays.

we can able to achieve this by using a function called make().

func main() {// declaring a slice of slices of type integer with a length of 3.slice_of_slices := make([][]int , 3)for i := 0; i < 3; i++ { // looping through the slice to declare slice of slice of length 3
slice_of_slices[i] = make([]int, 3)
// assigning values to each slice of a slice
for j := 0; j < 3; j++{
slice_of_slices[i][j] = i * j
}
}// printing the slice of slices matrix
for i := 0; i < 3; i++ {
fmt.Println(slice_of_slices[i])
}
fmt.Println("Slice of slices: ", slice_of_slices)
}

It is possible to have a variable slice of slices due to their dynamic nature.

func main() {
// declaring a slice of slices of type integer with a length of 3
slice_of_slices := make([][]int , 3) for i := 0; i < 3; i++ {
new_length := i * 2 + 1
// looping through the slice to declare slice of slice of a variable lengthslice_of_slices[i] = make([]int, new_length)// assigning values to each slice of a slice for j := 0; j < new_length; j++{
slice_of_slices[i][j] = i * j + 1
}
}// printing the slice of slices matrixfor i := 0; i < 3; i++ {
fmt.Println(slice_of_slices[i])
}
fmt.Println("Slice of slices: ", slice_of_slices)}

ADD ITEMS TO SLICE USING APPEND :

slc2 := []int{78, 50,70} //create slicefmt.Println("Slc1 before append :", slc1) //[78,50,70]slc1 = append(slc1, 10, 20)fmt.Println("Slc1 after append :", slc1) //[78,50,70,10,20]

UPDATE SLICE ITEM VALUE :

fmt.Println("before update : ", slc1) //[78,50,70]slc1[2] = 27 //updated index 2 value(70) in slc1 to 27fmt.Println("After update : ", slc1) //[78,50,27]

ACCESS SLICE ITEM VALUE :

fmt.Println(slc1[0]) // 78
fmt.Println(slc1[1]) // 50
fmt.Println(slc1[0:3]) // [78,50,70]

APPEND TWO SLICES :

If there’s sufficient capacity in the underlying slice, the element is placed after the last element and the length get incremented. However, if there is not sufficient capacity, a new slice is created, all of the existing elements are copied over, the new element is added onto the end, and the new slice is returned.

slc2 := []int{2,3,7}
fmt.Println("Before Append : ", slc2)//[2,3,7]
slc2 = append(slc2, slc1...)
fmt.Println("After Append : ", slc2)//[78,50,70,2,3,7]

DELETE ELEMENTS FROM SLICE :

slc1 = removeIndex(slc1, index)

Approch-1: If you want to maintain order……

func removeIndex(slc1 []int, index int) []int {
return append(slc1[:index], slc1[index+1:]...)
}

This is inefficient because you may end up with moving all of the elements, which is costly.

Aproch-2: If you don’t want to maintain order….

func removeIndex(slc1 []int, index int) []int {
return append(slc1[:index], slc1[index+1:]...)
}

ITEM EXIST IN GIVEN SLICE :

func isItemExists(slc1 []int, item int) bool {
for _, ele := range slc1 {
if ele == item {
return true
}
}
return false
}

--

--

Sivareddy Uppathi

Full Stack Software Developer| Programming enthusiast | Loves DS-Algo and System Design