Go - Variable Declaration, Pointers, Slices, and Arrays

Contemporary Programming Languages - CS2001 - 26 October 2017

Variable Declaration

  • Because unused Variables are a compiler error, it is common practice to declare variables right before you’re going to use them.
  • Don’t worry about trying to declare all variables at top of function.
    // yes
    var x int64;
    x = 3;
    var y int8
    // no
    var x int64
    var y int8
    x = 3
    

Constants

const A = "frog"
const B string = "frog"
const(
  x string = "frog"
  y int = 10
  z = false
)

Pointers

  • A pointer stores the address of a varaible of a given trype
    • var x *int // a pointer named x that points to an int
    • var y *[3]int // a pointer named y that points to an array of 3 ints
    • The zero value for a pointer is nil
    • Go does not permit pointer arithmatic
package main
import "fmt"
func main() {
  x: := [3]int {1,2,3} // [3]int
  y := x // [3]int
  fmt.Println(x) // [1, 2, 3]
  fmt.Println(y) // [1, 2, 3]
  y[1] = 10
  fmt.Println(x) // [1, 2, 3]
  fmt.Println(y) // [1, 10, 3]
}

Only dealing with values in above example, copying occurs

With Pointers:

func main() {
  x: := &[3]int {1,2,3} // *[3]int
  y := x // [3]int
  fmt.Println(x) // [1, 2, 3]
  fmt.Println(y) // [1, 2, 3]
  y[1] = 10
  fmt.Println(x) // [1, 10, 3]
  fmt.Println(y) // [1, 10, 3]
}

Allocating Memory

  • How do I know I my variables are on the heap or stack?
    • It doesn’t matter, don’t worry about it.
    • The compiler, runtime, and garbage collector handle everything.
  • new(T)
    • Allocate storage for a variable of type T at runtime.
    • Returns a pointer *T pointing to the allocated variable.
    • The pointed-to value is zeroed.
      x := new(int) // *int x = 0
      var y *int // *int y = nil
      
  • make(T, args)
    • Creates slices, maps, and channels
    • Returns an initialized value of type T (not *T)
      • Slices, maps, and channels require allocation and initialization before use.
func main() {
  x := new([3]int)
  y := x
  y[1] = 5
  fmt.Println(x) // [0, 5, 0]
  fmt.Println(y) // [0, 5, 0]
}

As you can see, all values were initialized as 0

// Idiomatic
x := &[3]int {1, 2, 3}

// Garbage
x := new([3]int)
x[0] = 1
x[1] = 2
x[2] = 3

Just because the new operator exists doesn’t mean it is always the best option.

func main() {
  x := make([]int, 3, 10) // 3 = length, 10 = capacity(optional) x is []int right now, not a pointer
  y := x
  y[1] = 5
  fmt.Println(x) // [0, 5, 0] Why is this?
  fmt.Println(y) // [0, 5, 0]
}

This is because a slice is basically an ArrayList, and that means that there is a backing array larger than the slice. The slice itself is basically a pointer to the array with a length and capacity to restrict access. y is set to x, and since the slice is a pointer, it still points to the same array.

Slices/Arrays

Indexing

  • Indexes must be non-negative ints
  • Accessing index x of array/slice A outside of the range 0 <= x < len(A) causes a runtime panic (very bad, do not catch these, they shouldn’t exist)

Creating Slices

  • Literal Slice
    s := []int {1, 2, 3, 4, 5, 6}
    s[0] // 1
    s[1:3] // [2, 3] <- a slice
    len(s) // 6
    cap(s) // 6
    

    if we t := s[1:3] this will have len of 2 and capacity of 5 since the start moved

  • Using make()
    s := make([]int, 6, 10)
    s[0] // 0
    t := s[1:3] // [0, 0]
    len(s) // 6
    cap(s) // 10
    len(t) // 2
    cap(t) // 9
    

Slicing Arrays and Slices

a := [8]int {1, 2, 3, 4, 5, 6, 7, 8}
s := a[2:len(a)-2] // This is the idiomatic way to negative index.
len(s) // 4
cap(s) // 6
fmt.Println(s) // [3, 4, 5, 6]
s[0] // 3
t := s[1:3] // [4, 5]
len(t) // 2
cap(t) // 5
s[4] // runtime panic!!

a[4] = 33
fmt.Println(s) // [3, 4, 33 ,6] (a is the backing array!)

EVERYTHING ABOUT SLICES IS PRIME TEST MATERIAL

Operators

  • + sum
    • int float cplx string
  • - difference
    • int float cplx string
  • * product
    • int float cplx
  • / difference
    • int float cplx
  • % remainder
    • int float cplx
  • & bitwise and
    • int
  • | bitwise or
    • int
  • ^ bitwise xor
    • int
  • << left shift
  • >> right shift

  • ++, –
    • These are statements, not expressions
      x := 0
      y := x++ // Nope