Tuesday, April 29, 2014

Working With Golang Array Slices

In the Go language a Slice is equivalent to the way a Perl/Python developer might think of an Array.  Yes, there is an actual Array under the covers of a Slice, but you cannot do much with them. So in Go, most people works with a Slice.  So if you are new to Go and coming from Perl/Python or the like, when you think you want an Array, you really want a Slice.  

Example
package main

import (
 "fmt"
)

func main() {
 
 // This is how you would declare and initialize a Slice at the same time.
 var aSliceOfStrings1 = []string{"a", "b", "c"}
 fmt.Println(aSliceOfStrings1[1])
 // This will print "b"


 // This is a shorthand way of declaring and initializing a Slice at the same time.
 aSliceOfStrings2 := []string{"c", "d",}
 fmt.Println(aSliceOfStrings2[1])
 // This will print "d" 

 
 // To create a slice but not initialize it you would use the make function.  This allows to define the
 // size and the optional capacity (defaults to length) at the same time.
 aSliceOfStrings3 := make([]string, 5, 10)
 aSliceOfStrings3[0] = "a"
 aSliceOfStrings3[1] = "b"
 aSliceOfStrings3[2] = "c"
 aSliceOfStrings3[3] = "d"
 aSliceOfStrings3[4] = "e"
 fmt.Println(aSliceOfStrings3[0])
 // This will print "a"


 // Append a Slice with more data
 aSliceOfStrings3 = append(aSliceOfStrings3, "f", "g", "h")
 fmt.Println(aSliceOfStrings3[6])
 // This will print "g"

 // Get the length and capacity of a Slice
 l := len(aSliceOfStrings3)
 fmt.Println("Length: ", l)
 // This will print "Length: 8"

 c := cap(aSliceOfStrings3)
 fmt.Println("Capacity: ", c)
 // This will print "Capacity: 10"

 // Copy an element of a Slice
 i := aSliceOfStrings3[1]
 fmt.Println(i)
 // This will print "b"


 // Copy part of a Slice in to another Slice, end needs to be what you want + 1 so if we want [2:4] we need to say [2:5]
 // You can also say [:] to mean the entire Slice. 
 // [:2] means the start of the Slice to the second element. 
 // And [2:] to mean from the second element to the end of the Slice.
 anotherSliceOfStrings1 := aSliceOfStrings3[2:5]
 fmt.Println("Length: ", len(anotherSliceOfStrings1))
 fmt.Println("Capacity: ", cap(anotherSliceOfStrings1))
 fmt.Println(anotherSliceOfStrings1[0])
 fmt.Println(anotherSliceOfStrings1[2])
 // This will print "Length: 3"
 // This will print "Capacity: 8" since we removed the first 2 elements of the original Slice
 // This will print "c" and "e"

 anotherSliceOfStrings2 := aSliceOfStrings3[:2]
 fmt.Println("Length: ", len(anotherSliceOfStrings2))
 fmt.Println("Capacity: ", cap(anotherSliceOfStrings2))
 fmt.Println(anotherSliceOfStrings2[0])
 fmt.Println(anotherSliceOfStrings2[1])
 // This will print "Length: 2"
 // This will print "Capacity: 10" the start of the Slice did not change so the capacity is the same
 // This will print "a" and "b" 

 anotherSliceOfStrings3 := aSliceOfStrings3[4:]
 fmt.Println("Length: ", len(anotherSliceOfStrings3))
 fmt.Println("Capacity: ", cap(anotherSliceOfStrings3))
 fmt.Println(anotherSliceOfStrings3[0])
 fmt.Println(anotherSliceOfStrings3[1])
 // This will print "Length: 4"
 // This will print "Capacity: 6" the start of the Slice changed so the capacity did as well
 // This will print "e" and "f"
}




Passing Slices to Functions
It's important to understand that even though a slice contains a pointer, it is really a value that under the covers is a struct value holding a pointer and a length. It is not a pointer to a struct. 

This matters when you pass a Slice to a function.  When you pass a Slice to a function you can modify the values in the Slice in the function and they will keep, however,  you can not modify the header (aka the length and capacity) as the header was passed by value not as a pointer.  If you want to modify the header, then you need to pass the Slice as a pointer not as a value.    You pass a Slice as a pointer by preceding it with an “&”.  Here is an example to replicate the "shift" function in Perl.

package main

import ("fmt")

var DEBUG int = 0

// This function tries to replicate the shift function in Perl by removing the first
// element of an slice and returning it
func Shift (pToSlice *[]string) string {
    sValue := (*pToSlice)[0]
    if DEBUG == 1 {
        fmt.Println("The slice before the shift: ",  *pToSlice)
    }
    *pToSlice = (*pToSlice)[1:len(*pToSlice)]
    
    if DEBUG == 1 {
        fmt.Println("The slice after the shift: ",  *pToSlice)
    }
    return sValue    
}


func main() {
    var a = []string{"1", "2", "3", "4"}
    for i := range a {
        fmt.Println(a[i])
    }
    // This will print 1, 2, 3, 4


    test := Shift(&a)
    fmt.Println("This is the shifted value: ", test)
    // This will print 1


    test2 := Shift(&a)
    fmt.Println("This is the shifted value: ", test2)
    // This will print 2
    
    for i := range a {
        fmt.Println(a[i])
    } 
    // This will print 3, 4
}




 

No comments:

Post a Comment