Golang basics

Old notes about golang basic syntax and features

this is an old study notes about golang, when I was first learning its syntax and nice features.

Imports


  import "fmt";
  import "math";

  // OR

  import (
    "fmt"
    "math"
  )

Exports

Exports begins with capital letter


  import (
    "fmt"
    "math"
  )

  func main() {
    fmt.Println(math.Pi)
  }

Note Println and Pi, they are exported.

Functions

func add(x int, y int) int { return x + y }

If two or more arguments have the same type, you can do: add(x, y int)

A function can return multiple results:


  func swap(x, y string) (string, string) {
    return y, x
  }

You can name the returned values like so:


  func split(sum int) (x, y int) {
    x = sum * 4 / 9
    y = sum - x
    return
  }

When passing arguments into a function, if it’s passed by value (like a string), it will basically copy the value and you can modify the value inside the function:


  func main() {
    greeting := 'Hello'
    name := 'Ricardo'
    sayGreeting(greeting, name)
    fmt.Println(name)
  }

  func sayGreeting(greeting, name string) {
    fmt.Println(greeting, name)
    name = 'Ted'
    fmt.Println(name)
  }

  // RESULT
  Hello Ricardo
  Ted
  Ricardo

The name is only modified inside the sayGreeting function But if we pass a pointer to the value?


  func main() {
    greeting := 'Hello'
    name := 'Ricardo'
    sayGreeting(&greeting, &name)   // pass the address
  }

  func sayGreeting(greeting, name *string) {  // make sure it's a pointer
    fmt.Println(*greeting, *name)   // dereference the pointers to display the values
    *name = 'Ted'   // dereference pointer and assign a new value
    fmt.Println(*name)
  }

  // RESULT
  Hello Ricardo
  Ted
  Ted

Now we’ve changed the value not only in the scope of the function, but outside too. We do that because:

You also can do something like a spread operator, but it only works as the last parameter of a function:


  func main() {
    sum(1, 2, 3, 4, 5)
  }

  func sum(values ...int) {
    fmt.Println(values)
    result := 0
    for _, v := range values {
      result += v
    }
    fmt.Println(result)
  }

Go can do something unusual. The return value of a function can be a local variable returned as a pointer:


  func sum(values ...int) *int {   // return type is a pointer integer
    fmt.Println(values)
    result := 0
    for _, v := range values {
      result += v
    }
    return &result   // return the address of result
  }

We also can do a named return, which means we don’t have to declare the variable name inside the function, neither return it. The syntax is like this:


  func sum(values ...int) (result int) {  // define the result variable here
    fmt.Println(values)
    result := 0
    for _, v := range values {
      result += v
    }
    return    // return the result is implicit
  }

In Go we can have two return values from a function. That’s very usefull when dealing with function that can give us an error. So we return an error value as a second argument, and deal with the error in the higher function:


  func main() {
    d, err := divide(5.0, 0.0)
    if err != nil {
      fmt.Println(err)
      return
    }
    fmt.Println(d)
  }

  func divide(a, b float64) (float64, error) {
    if b == 0.0 {
      return 0.0, fmt.Errorf("Cannot divide by zero")
    }
    return a / b, nil
  }

This above is a very commom pattern in Go.

Functions themselves can be threated as values, can be passed around and everything. Usually to work with functions as values you use the anonymous function:


  func main() {
    var f func() = func() {
      fmt.Println("Anonymous")
    }
    f()
  }

A more complex example would be:


  func main() {
    var divide func(float64, float64) (float64, error)
    divide = func(a, b float64) (float64, error) {
      if b == 0.0 {
        return 0.0, fmt.Errorf("Cannot divide by zero")
      } else {
        return a / b, nil
      }
    }
    d, err := divide(5.0, 3.0)
    if err != nil {
      fmt.Println(err)
      return
    }
    fmt.Println(d)
  }

Above, we are declaring the variable which will hold the function, with it’s args and return value types. Then we assign the anonymous function to the divide variable. Then retrieving the returned values from divide into variables d, err

Now let’s talk about functions as methods. A method is basically a function executed within a context:


  func main() {
    g := greeter{
      greeting: "Hello",
      name: "Go",
    }
    g.greet()
  }

  type greeter struct {
    greeting string
    name strig
  }

  func (g greeter) greet() {
    fmt.Println(g.greeting, g.name)
  }

The method is basically a function inside the type. In this case the type is a struct called greeter. So you can define a struct, above is called g and then call the method g.greet()

Everytime you call a method you pass the copy of the type, in this case a copy of the struct greeter. If you want, you can pass a pointer, so everything you do will change the underlying struct too:

func (g *greeter) greet() { ... }

Variables

var declares a list of variables. It can be declared inside or outside the function.


  var c, python, java bool

  func main() {
    var i int
    fmt.Println(i, c, python, java)
  }

Variables can be declared with initial values:

var i, j int = 1, 2

If there is an initial value, the type can be omitted, since the variable will have the type of the initial value:

var c, python, java = true, false, "no!"

Inside a function, variables with initial values can be declared in a short declaration:


  func main() {
    k := 3
    c, python, java := true, false, "no!"
  }

Variables can be factored declared like import statements:


  var (
    ToBe   bool       = false
    MaxInt uint64     = 1<<64 - 1
    z      complex128 = cmplx.Sqrt(-5 + 12i)
  )

Variables declared without a value are given zeroed values

We can use constants for declaring varibles, using const. They cannot be declared with := syntax

const Truth = true

Constants

We can define a const block and use the special value iota to create enumerated expressions.

iota starts at 0 value and increment by one each time:


  const (
    a = iota  // 0
    b         // 1
    c         // 2
    d         // 3
  )

  const (
    isAdmin = 1 << iota  // 1 or 00000001
    isHeadquarters      //  2 or 00000010
    canSeeFinancial     //  4 or 00000100

    canSeeAfrica        //  8 or 00001000
    canSeeAmerica      //  16 or 00010000
    canSeeAsia         //  32 or 00100000
    canSeeEurope       //  64 or 01000000
  )

  func main() {
    var roles byte = isAdmin | canSeeFinancial | canSeeAmerica
    fmt.Printf("%b
", roles)

    fmt.Printf("canSeeFinancial? %v
", canSeeFinancial & roles == canSeeFinancial)
  }

  // RESULT
  10101 (00010101 with 8 bytes)
  canSeeFinancial? true

In the snippet above, we can see if a user has a permission to do something, for example.

With this line: var roles byte = isAdmin | canSeeFinancial | canSeeAmerica we use the OR operator to store these values in a byte variable called roles. The result is: 10101 because:

Now, in this line: fmt.Printf("canSeeFinancial? %v\n", canSeeFinancial & roles == canSeeFinancial) we use a AND mask canSeeFinancial & roles to get the byte that has canSeeFinancial (third house, 00000100), which is value 4, and see if it’s equal (==) canSeeFinancial value (which is 4). This evaluates to true, therefore, canSeeFinancial equals true

Types

Go basic types are:

You can convert types using T(value):


  var i int = 42
  var f float64 = float64(i)
  var u uint = uint(f)

  // OR

  i := 42
  f := float64(i)
  u := uint(f)

When declaring numeric variables, the type of the variable depends on the precision of the value:


  i := 42           // int
  f := 3.142        // float64
  g := 0.867 + 0.5i // complex128

Bit Operators


  func main() {
    a := 10
    b := 3
    fmt.Println(a & b)
    fmt.Println(a | b)
    fmt.Println(a ^ b)
    fmt.Println(a &^ b)
  }

  // RESULTS
  2
  11
  9
  8

Why these weird results? We have to see the binary representation to understand

a := 10 // 1010 b := 3 // 0011

So for the & (and) operator, we compare the bits in each house to see if there is a bit in a AND in b. The result is:

0010 (2 in decimal) because the third house is the only place there is a bit in both a and b

The | (or) operator check if there is a bit in a or in b. Therefore, the result is: 1011 (because there are bits in the first house, third house and fourth house). 1011 binary is 11 in decimal

Bitshifting


  func main() {
    a := 8
    fmt.Println(a << 3)
    fmt.Println(a >> 3)
  }

  a := 8 is basically 2^3. If we bitshift to the left 3 places (a << 3) it will basically do 2^3 * 2^3 = 2^6 (64)

  The a >> 3 will bitsift to right 3 places: 2^3 / 2^3 = 2^0 (1)

For loop

Go has only one looping construct, the for loop. Is a normal for loop, with three components:


  func main() {
    sum := 0
    for i := 0; i < 10; i++ {
      fmt.Println(sum)
      sum += i
    }
    fmt.Println(sum)
  }

The init and post statement are optionals:


  func main() {
    sum := 1
    for ; sum < 1000; {
      sum += sum
    }
    fmt.Println(sum) // 1024
  }

A while loop can be done as for loop in Go:


  func main() {
    sum := 9757
    for sum < 100 {
      sum += sum
    }
    fmt.Println(sum)
  }

You can initialize two or more variables in the loop:


  for i, j := 0, 0; i < 5; i, j = i+1 j+1 {
    fmt.Println(i, j)
  }

We can create a infinite for loop, with the conditional inside the for loop and a break keyword to exit the loop:


  i := 0
  for {
    fmt.Println(i)
    i++
    if i == 5 {
      break
    }
  }

We can also use the continue keyword, so the for loop exits the current loop, and goes to the next one:


  for i := 0; i < 10; i++ {
    if i%2 == 0 {
      continue
    }
    fmt.Println(i)
  }

This code above will print only odd numbers (ímpar).

If you have nested for loops and you want to break the loop (the inner and outer loop), you can use a label:


  Loop:
    for i := 1; i <= 3; i++ {
      for j := 1; j <= 3; j++ {
        fmt.Println(i * j)
        if i * j >= 3 {
          break Loop
        }
      }
    }

  // RESULT
  1
  2
  3

So now when the conditional pass, we will stop the loop using the label Loop, which is breaking the outer loop (because it’s positioned before the outer loop)

To use a for loop with a collection, say a slice, we use the for range syntax (because we may not know the size of the collection at runtime)


  func main() {
    s := []int{1, 2, 3}
    for k, v := range s {
      fmt.Println(k, v)
    }
  }

  // RESULT
  0 1
  1 2
  2 3

So range will give us the key and value of each item in the slice, which we are storing inside the k and v variables.

If statement


  if x < 0 {
    fmt.Printf("X is like: %v
", x)
    return sqrt(-x) + "i"
  }

Like for loops, if don’t use () and {} are required.

Also like the for loop, if statements can have a short statement before the loop:


  if v := math.Pow(x, n); v < lim {
    return v
  }

v is only scoped inside the if/else statement


  func pow(x, n, lim float64) float64 {
    if v := math.Pow(x, n); v < lim {
      return v
    } else {
      fmt.Printf("%g >= %g
", v, lim)
    }
    // can't use v here, though
    return lim
  }

Another example of a if statement with a initializer:


  if pop, ok := statePopulations["Florida"]; ok {
    fmt.Println(pop)
  }

The ok is the test case for the if statement. Everything behind is just a initializer, a expression.

When comparing floating point numbers, there is a gotcha! The best approach to compare them is not by using ==, because the decimals can be a bummer. The best solution is to divide the numbers and subtract 1, to get the remainer. And now you compare this remainer, to see if it’s smaller than a certain number (like 0.001). If is true, we can consider the numbers being equal.


  func main() {
    myNum := 0.123
    if math.Abs(myNum / math.Pow(math.Sqrt(myNum), 2) - 1) < 0.001 {
      fmt.Println("These are the same")
    } else {
      fmt.Println("These are different")
    }
  }

Switch statement

Go’s switch case cannot be constants and the values cannot be integers


  func main() {
    fmt.Print("Go runs on ")
    switch os := "linux"; os {
    case "darwin":
      fmt.Println("OS X.")
    case "linux":
      fmt.Println("Linux.")
    default:
      // freebsd, openbsd,
      // plan9, windows...
      fmt.Printf("%s.
", os)
    }
  }

We can use switch statements without a condition (which always evaluate to true) in order to write cleaner if/else statements:


  func main() {
    t := time.Now()
    switch {
    case t.Hour() < 12:
      fmt.Println("Good morning!")
    case t.Hour() < 17:
      fmt.Println("Good afternoon.")
    default:
      fmt.Println("Good evening.")
    }
  }

We can use more than a case:


  switch 5 {
    case 1, 5, 10:
      fmt.Println("Entrou)
    case 2, 3, 11:
      fmt.Println("Nahh")
    default:
      fmt....
  }

You can put the comparisson inside the case:


  i := 10
  switch {
    case i <= 10:
      fmt.Println("Umm")
      fallthrough
    case i <= 20:
      fmt.Println("Doiss")
    default:
      fmt.Println("defaultt")
  }

We can use a switch case to check the type:


  var i interface{} = 1
  switch i.(type) {
    case int:
      fmt.Println("Integer")
    case float64:
      fmt.Println("Float64")
    case string:
      fmt.Println("String")
    default:
      fmt.Println("Another")
  }

You can put a break keyword inside the case, if you want to stop the case before something happens. For example, you can use a if statement and if evaluates to true, you use the break.

Defer

We can use defer to wait for surrounding functions to return, before run the deffered function

func main() {
	defer fmt.Println("world")

	fmt.Println("hello")
	fmt.Println("WAAAAIT")
}

// OUTPUT

hello
WAAAAIT
world

Deferred function calls are pushed onto a stack. When a function returns, its deferred calls are executed in last-in-first-out order.

func main() {
	fmt.Println("counting")

	for i := 0; i < 10; i++ {
		defer fmt.Println(i)
	}

	fmt.Println("done")
}

// OUTPUT

counting
done
9
8
7
6
5
4
3
2
1
0

Pointers

A pointer has the memory address of a value.

Putting * in front of a TYPE indicates a pointer to it’s value:

var p *int

This above will be a pointer to an integer.

The & generates a pointer to it’s operand:

i := 42
p = &i

So the long form would be:

var a int = 42
var b *int = &a

// RESULT
42
0x414020

The & operator in front of a value indicates the memory address of the value:

fmt.Println(&a)

The * operator in front of a value indicates the pointer’s underlying value:

fmt.Println(*p) // read i through the pointer p
*p = 21 // set 21 through the pointer p

Read a pointer’s value is known as dereferencing or indirecting

func main() {
	i, j := 42, 2701

	fmt.Println(&i)
	fmt.Println(&j)

	p := &i         // point to i
	fmt.Println(*p) // read i through the pointer
	*p = 21         // set i through the pointer
	fmt.Println(i)  // see the new value of i

	p = &j         // point to j
	*p = *p / 37   // divide j through the pointer
	fmt.Println(j) // see the new value of j
}

// RESULTS:

0x414020
0x414024
42
21
73

In other languages you have something called pointer arithmethics, where you can do calculations on pointers:

func main() {
  a := [3]int{1, 2, 3}
  b := &a[0]
  c := &a[1]
  fmt.Printf("%v %p %p\n", a, b, c)
}

// RESULT
[1, 2, 3] 0x1040a124 0x1040a128

Note that c is only 4 bytes higher than b. It’s because in this system an integer is 4 bytes long. So if you come from another language like C, you might want to do this:

c := &a[1] - 4

Now, by theory, you would be doing something like 0x1040a128 - 4, which will point to b. But Go does not support this. If you reeeeally want to do this, use the unsafe package by Go.

Pointer types:

type myStruct struct {
	foo int
}

func main() {
	var ms *myStruct
	ms = &myStruct{foo: 42}
	fmt.Println(ms)
}

// RESULT
&{42}

The response above means that ms is holding the address of an object with a field 42.

We can also initialize a variable to point to a object with the new function:

var ms *myStruct
ms = new(myStruct)
fmt.Println(ms)

If you declare a pointer like var ms *myStruct but don’t initialize, it will get a <nil> value.

To set, or get a value from a pointer, you have to dereference it and do your thing:

var ms *myStruct
ms = new(myStruct)
(*ms).foo = 42  // SET A VALUE
fmt.Println((*ms).foo)  // GET A VALUE

BUT we don’t need to do that in Golang. The compiler is smart enough to know we want to handle the underlying object, so Go will derefence the pointer:

ms.foo = 42 fmt.Println(ms.foo)

This will work.

Now some important facts:

be carefull when passing slices and maps in your app struct, arrays and other data structs don’t have this behavior

Structs

It’s a collection of fields, acessed by a dot

Struct gathers informaion together, related to a concept, and it’s very flexible because we can mix the types together. All other data structures have to have the same types (arrays, slices)..

type Doctor struct {
  number int
  name string
  companions []string
}

func main() {
  aDoctor := Doctor{
    number: 3,
    name: "Ricardo Han",
    companions: []string{
      "Stella",
      "Jeff",
    },
  }
}

To get a specific value: fmt.Println(aDoctor.companions[1])

We can use positional fields when declaring structs:

aDoctor := Doctor{
  3,
  "Ricardo Han",
  []string{
    "Stella",
    "Jeff",
  },
}

When declaring a Struct type, it follows the name rules for exported variables in Go: if is lowercase, is available only inside the file, if is Uppercase, it will be exported and available outside as well. So a exported Struct type would be like:

type Doctor struct {
  Number int
  Name string
  Companions []string
}

Intead of declaring a Struct like the above, we can declare a anonymous Struct:

aDoctor := struct{name string}{name: "Ricardo Han"}

You can’t use it anywhere else, but you can use it where you declare it.

Structs are values, so when assign the original Struct to another variable and change it, the original Struct will remain unchanged:

aDoctor := struct{name string}{name: "Ricardo Han"}
anotherDoctor := aDoctor
anotherDoctor.name = "John Baker"

fmt.Println(aDoctor)
fmt.Println(anotherDoctor)

// {Ricardo Han}
// {John Baker}

So when you pass Structs around in your app, it will create a copy everytime. If you want to manipulate the same original data, use a pointer:

anotherDoctor := &aDoctor

type Vertex struct {
	X int
	Y int
}

func main() {
	v := Vertex{1, 2}
	fmt.Println(v.X)
}

We can access a struct through a struct pointer. You could access the struct values by doing (if p was a pointer):

(*p).X, but in Go you can access values of a struct directly from a pointer as p.X

You can allocate new values for the struct also using the struct literals

type Vertex struct {
	X, Y int
}

var (
  v1 = Vertex{1, 2}
  v2 = Vertex{X: 1} // Y will be 0
  v3 = Vertex{Y: 1} // X will be 0
)

Arrays

var a [10]int is an array of ten integers

The array’s length in part of it’s type, so arrays in Go cannot be resized. This seems limiting, but don’t worry: Go provides a convenient way of working with arrays.

func main() {
	var a [2]string
	a[0] = "Hello"
	a[1] = "World"
	fmt.Println(a[0], a[1])
	fmt.Println(a)

	primes := [6]int{2, 3, 5, 7, 11, 13}
	fmt.Println(primes)
}

When you initialize an array, you don’t have to declare the size of the array, just pass [...] and it will automatically fit the contents of the array:

grades := [...]int{1, 2, 3}

To check the length of array: len(grades)

It can be an array of arrays: identity := [2][2]int{ [2]int{1,2}, [2]int{3,4} } So we are declaring an array with 2 array, that will have 2 integers inside: var identity [2][2]int

In Go, the arrays are actuall values, they are not passed by reference as in Javascript. So if you declare and array a, and then assign that array to b, you will have two different array.

If you don’t want this behaviour, you can use pointers to point to the same data:

a := [...]int{1, 2, 3}
b := &a

Now b is pointing to the same data as a

Slices

Slices offers a flexible view into element of an array. A slice is formed by two values: a low and high bound. eg: a[low:high] int

func main() {
	primes := [6]int{2, 3, 5, 7, 11, 13}

	var s []int = primes[0:4]
	fmt.Println(s)
}

// RESULT

[2 3 5 7]

In the example above, s is a slice that gets the 0 index until (but not including) the 4° index.

a := []int{1, 2}
b := a

a and b reference to the same array

We can create slice literals by declaring the same as an array, but without the length:

Array literal: [3]bool{true, true, false} Slice literal: []bool{true, true, false}

When creating a slice, you can omit the low and high value and use their defaults instead. The defaults are 0 for low and the slice length for high:

Array is like: var a [10]int

Slices are like:

a[0:10]
a[:10]
a[0:]
a[:]

// they are all the same!

The many ways of creating a slice:

func main() {
  a := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
  b := a[:] // create a slice with all the element of a
  c := a[3:] // create slice from 4th element (index 3) until the end (4 to 10)
  d := a[:6] // create slice until 6th element (index 5) (1 to 6)
  e := a[3:6] // from index 3 (4th element) until 6th element (4 to 6)
}

It’s confusing because the numbers inside have different meaning. You can think of to as including the index and from excluding the index. So a[3:6] includes element of index 3 until (but excluding) element of index 6.

A slice has length and capacity.

The length of a slice is the number of elements it contains. len(s)

The capacity of a slice is the size of the backing array, is the number of elements in the underlying array, counting from the first element in the slice. cap(s)

We can extends the slice length by re-slicing it, providing a bigger high value.

The zero value of a slice is nil

Slices can be created with make function. To create dinamically-sized-array, we can use it.

The 1° parameter is the type and the second is the size of the slice:

a := make([]int, 3)

The make function allocates a zeroed array and returns a slice that refers to that array:

a := make([]int, 5) // len(a)=5

To specify a capacity, we pass a 3° arg:

b := make([]int, 0, 5) // len(b)=0, cap(b)=5

b = b[:cap(b)] // len(b)=5, cap(b)=5
b = b[1:]      // len(b)=4, cap(b)=4

It’s usefull to have different capacity because, unlike array, slices can have a flexible size, adding and removing elements during their lifecycle.

If we declare a empty slice, and then begin appending data inside, Go will copy the underlying array to a new array with the content size. So doing this every time can be expensive for the memory. It’s better to use a make function, define a bigger capacity and then begin assigning data to the slice.

Slices can contain any type, including other slices:

func main() {
  board := [][]string{
    []string{"_", "_", "_"},
    []string{"_", "_", "_"},
    []string{"_", "_", "_"},
  }
}

To append new elements to a slice, we can use the built-in append function

func append(s []T, vs ...T) []T

func main() {
	var s []int
	printSlice(s)

	// append works on nil slices.
	s = append(s, 0)
	printSlice(s)

	// The slice grows as needed.
	s = append(s, 1)
	printSlice(s)

	// We can add more than one element at a time.
	s = append(s, 2, 3, 4)
	printSlice(s)
}

func printSlice(s []int) {
	fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}

There is something like spread operator in Go, where you can use to concatenate slices for example:

a := []int{}
a = append(a, []int{1, 2, 3}...)

// RESULT
[1, 2, 3]

Above, we are appending a slice of 3 integers into the a slice, using the spread operator

Another operations for slices:

a := []int{1, 2, 3, 4}
b := [1:]
fmt.Println(b)

// [2, 3, 4]
a := []int{1, 2, 3, 4}
b := [:len(a) - 1]
fmt.Println(b)

// [1, 2, 3]
a := []int{1, 2, 3, 4, 5}
b := append(a[:2], a[3:]...)
fmt.Println(b)

// [1, 2, 4, 5]

Map

A map maps keys to values.

statePopulations := map[string]int {
  "California": 39250017,
  "Texas": 2799328,
  "Florida": 846626,
}

The make function returns a map of the given type, initialized and ready for use.

To get a value from the map:

statePopulations["Ohio"]

To add a key/value:

statePopulations["Georgia"] = 1083828

The order of a map is not guarantee, it not follows the same order of the entries.

To delete something from a map:

delete(statePopulations, "Georgia")

To check if there is a key inside the Map, we can use the comma okay syntax:

_, ok := statePopulations["Ohio"]

To see the length:

len(statePopulations)

When you pass a Map somewhere, it is passed by reference! So you are manipulating the same Map structure.

type Vertex struct {
	Lat, Long float64
}

var m map[string]Vertex

func main() {
	m = make(map[string]Vertex)
	m["Bell Labs"] = Vertex{
		40.68433, -74.39967,
	}
	fmt.Println(m["Bell Labs"])
}

// RESULT

{40.68433 -74.39967}

Map literals are like struct literals, but the keys are required.

type Vertex struct {
	Lat, Long float64
}

var m = map[string]Vertex{
	"Bell Labs": Vertex{
		40.68433, -74.39967,
	},
	"Google": Vertex{
		37.42202, -122.08408,
	},
}

func main() {
	fmt.Println(m)
}

// RESULT

map[Bell Labs:{40.68433 -74.39967} Google:{37.42202 -122.08408}]

We could’ve ommited the types from the elements of the literal:

var m = map[string]Vertex{
	"Bell Labs": {40.68433, -74.39967},
	"Google":    {37.42202, -122.08408},
}

To insert an element in a map m:

m[key] = elem

Retrieve an element:

elem = m[key]

Delete an element:

delete(m, key)

Test if key is present, with a two-value:

elem, ok = m[key]

OR

elem, ok := m[key]

If key is in the map, ok is true and elem is the value of the element. Else, ok is false and elem is zero-value

Function Values

Functions can be values too, passed around like arguments, return values, in variables…

func compute(fn func(float64, float64) float64) float64 {
	return fn(3, 4)
}

func main() {
	hypot := func(x, y float64) float64 {
		return math.Sqrt(x*x + y*y)
	}
	fmt.Println(hypot(5, 12))

	fmt.Println(compute(hypot))
	fmt.Println(compute(math.Pow))
}

Function Closures

Go functions may be closures, which is a function value that references variables from outside its body.

For example, this function adder return a closure function (because it references the sum variable that lives outside it’s scope):

func adder() func(int) int {
	sum := 0
	return func(x int) int {
		sum += x
		return sum
	}
}

Methods

Go does not have classes, but it has methods. Methods are just function with a special receiver argument, between the func keyword and the method name:

type Vertex struct {
	X, Y float64
}

func (v Vertex) Abs() float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func main() {
	v := Vertex{3, 4}
	fmt.Println(v.Abs())
}

Here there is a method Abs with a receiver v of type Vertex

Since methods are just functions, here is Abs written as a regular function:

func Abs(v Vertex) float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func main() {
	v := Vertex{3, 4}
	fmt.Println(Abs(v))
}

You can define non-struct types in methods too:

type MyFloat float64

func (f MyFloat) Abs() float64 {
	if f < 0 {
		return float64(-f)
	}
	return float64(f)
}

Methods can have a pointer receiver, with the syntax of *T for a type T.

A pointer receiver modifies the value to which the pointer points (since is a pointer, is the same place in memory)

With a value receiver (not pointer), the method operates in a copy of the value, not the value itself.

type Vertex struct {
	X, Y float64
}

func (v Vertex) Abs() float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func (v *Vertex) Scale(f float64) {
	v.X = v.X * f
	v.Y = v.Y * f
}

func main() {
	v := Vertex{3, 4}
	v.Scale(10)
	fmt.Println(v.Abs())
}

// RESULT 50

In the example above, with (v *Vertex) being a pointer, the values of vertex change.

Methods with pointer receivers can take either a pointer or a value as argument, because Go will interpret thats as a pointer:

func (v *Vertex) Scale(f float64) {
	v.X = v.X * f
	v.Y = v.Y * f
}

func main() {
  v := Vertex{3, 4}
	v.Scale(2)
}

So the point is: in Methods, if you expect a pointer receiver and send a value, the value will be understood as a pointer. The reverse is also true: methods with value receivers take either a value or a pointer as the receiver when they are called.

There are two reasons to choose a pointer receiver for the method:

type Vertex struct {
	X, Y float64
}

func (v *Vertex) Scale(f float64) {
	v.X = v.X * f
	v.Y = v.Y * f
}

func (v *Vertex) Abs() float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func main() {
	v := &Vertex{3, 4}
	fmt.Printf("Before scaling: %+v, Abs: %v\n", v, v.Abs())
	v.Scale(5)
	fmt.Printf("After scaling: %+v, Abs: %v\n", v, v.Abs())
}

// RESULT

Before scaling: &{X:3 Y:4}, Abs: 5
After scaling: &{X:15 Y:20}, Abs: 25

Embedded

Go does not have inheritance, but it has composition

So supposed we have two Structs, Animal and Bird.

type Animal Struct {
  Name string
  Origin string
}

type Bird Struct {
  SpeedKPH float32
  CanFly bool
}

In other OOP languages, ‘Bird’ would BE and ‘Animal’. But in Go, is more like Bird HAS Animal properties

We use composition for that, it would be like this:

type Bird Struct {
  Animal
  SpeedKPH float32
  CanFly bool
}

func main() {
  b := Bird{}
  b.Name = "Emu"
  b.Origin = "Australia"
  b.SpeedKPH = 48
  b.CanFly = false
}

Through composition, now Bird struct has Animal properties

If you initialize the Bird with the values, you have to be aware of the Animal struct, and declare it like this:

b := Bird{
  Animal: Animal{Name: "Emu", Origin: "Australia"},
  SpeedKPH: 48,
  CanFly: false,
}

Generally you would use Interfaces for interchangeble data between types. But Embedding is usefull when you have a baseComponent and want to put the baseComponent types into other structures.

Tag

Used to describe information about a Struct field. Suppose you have to validate a input field, Tags are great for this:

import (
  "fmt"
  "reflect"
)
type Animal struct {
  Name string `required max:"100"`
  Origin string
}

func main() {
  t := reflect.TypeOf(Animal{})
  field, _ := t.FieldByName("Name")
  fmt.Println(field.Tag)
}

// RESULT

required max:"100"

The format of a Tag is to have backticks (“) and space-delimited key-value pairs (can be only a key also) The Tag itself is useless, it’s just a string. You have to get this information, with the reflect package.

Defer, Panic and Recover

Defer is how we can invoke a function but delay it’s execution. Panic is how a Go application can stop running, either the Go runtime trigger that as well as we can do it. Recovery is when the program panic, but we save the program so it does not bail out completely.

Defer

func main() {
	fmt.Println("Hello")
	defer fmt.Println("Middle")
	fmt.Println("Bye")
}

// RESULT
Hello
Bye
Middle

Go defer the function call and call it when the outer function finish, but before exit/return.

func main() {
	defer fmt.Println("Hello")
	defer fmt.Println("Middle")
	defer fmt.Println("Bye")
}

// RESULT
Bye
Middle
Hello

Defer is last in first out.

Now a common example when using defer, to close streams:

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
)

func main() {
	res, err := http.Get("http://www.google.com/robots.txt")
	if err != nil {
		log.Fatal(err)
	}
	defer res.Body.Close()
	robots, err := ioutil.ReadAll(res.Body)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s", robots)
}

We are making a request, opening a stream of bytes (robots) and printing it. But meanwhile, we are also defering and closing the res.Body, so it will close after the function executes.

a := "start"
defer fmt.Println(a)
a = "end"

// RESULT
start

You might think that the code above should print “end”, because the fmt.Println was defered. BUT, the defer get the arguments at the time it is declared. That’s why it prints “start”.

Panic

We don’t have exeptions in Go. But there are situations where a Go app cannot continue, so we use panic.

a, b := 1, 0
ans := a / b

fmt.Println(ans)

// RESULT

panic: runtime error: integer divide by zero

In this example, the Go runtime panic. But we also can call panic ourselves:

fmt.Println("Start")
panic("something bad happened")

Now let’s build a simple web server and panic in case there is an error:

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  w.Write([]byte("Hello Go!"))
})
err := http.ListenAndServe(":8080", nil)
if err != nil {
  panic(err.Error())
}

Now if, for example, we try to use the same PORT (8080), the app would give an error, but now we are using panic and it will shut down.

It’s important to note that defer it’s called BEFORE panic. So if we use defer to close a stream or something,it will close before panicing.

The order of execution of a function is:

But if we deal with a anonymous defer function, things roll a bit different:

func main() {
  fmt.Println("Start")
  panicker()
  fmt.Println("end")
}

func panicker() {
  fmt.Println("Its about to panick")
  defer func() {
    if err := recover(); err != nil {
      log.Println("Error:", err)
    }
  }()
  panic("something bad happened")
  fmt.Println("Done panicking")
}

In the code above, there is a anonymous function which is self invoking itself. Inside, the recover() return nil if the app is not panicing. If not null (if the app is panincing), will print the error.

So the panicker func will panic(), and then the defer func will be called, it will recover from the panic, print the error, and then go back to the main() func and print “end”.

You can re throw a panic inside the defer function, so the recover function don’t make your app follow the flow. This is usefull when you don’t know the error and wants to see what’s hapening:

defer func() {
  if err := recover(); err != nil {
    log.Println("Error:", err)
    panic(err)
  }
}()

Interfaces

Interface is a type, just like Structs or other types. But different from Structs, which define data inside them, interfaces describe behavior. So we will be storing meta-definitions

We created a method Write, which accepts a slice of bytes as args, and return an int and error Now to implement this interfacem let’s define a struct:

func main() {
  var w Writer = ConsoleWriter{}
  w.Write([]byte("Hello Go!"))
}

type Writer interface {
  Write([]byte) (int, error)
}

type ConsoleWriter struct {}

func (cw ConsoleWriter) Write(data []byte) (int, error) {
  n, err := fmt.Println(string(data))  // convert the bytes into a string and print to console
  return n, err
}

In Go we don’t explicity implement interfaces, it’s implicit by defining a method Write (same name as the Write method inside the interface) in the ConsoleWriter struct.

The advantage of interfaces is that, here:

func main() {
  var w Writer = ConsoleWriter{}
  w.Write([]byte("Hello Go!"))
}

The w variable is an intance o Writer interface, but it doesn’t know whats it’s being written to. It could be and TCPWriter, fileWriter or any other Writer (not just ConsoleWriter). This line w.Write([]byte("Hello Go!")) just knows it can call a Write method, but does not know to where is calling (this is the responsability of the implementation, in this case is calling to ConsoleWriter method.)

To follow a name convention, if your interface has only one method, use the name with er like Writer:

type Writer interface {
  Write([]byte) (int, error)
}

Name your interface by what it does.

You can implement interfaces to any type you can add methods. An example of an interface to an Int type:

func main() {
  myInt := IntCounter(0)
  var inc Incrementer = &myInt
  for i := 0; i < 10; i++ {
    fmt.Println(inc.Increment())
  }
}

type Incrementer interface {
  Increment() int
}

type IntCounter int   // we define a type alias for the int type, so we can add methods to it

// This below is the implementation for the Incrementer interface

func (ic *IntCounter) Increment() int {
  *ic++
  return int(*ic)
}

We are defining a method to our custom type IntCounter.

How to compose interfaces together:

type Writer interface {
  Write([]byte) (int, error)
}

type Closer  interface {
  Close() error
}

type WriterCloser interface {
  Writer
  Closer
}

You have to implement all the methods of the nested interfaces to be able to have the compose interface (WriterCloser in this case)

We also can type convert interfaces, if we want to get to the underlying type in case we want to work with them directly:

var wc WriterCloser = newBufferedWriterCloser()
bwc := wc.(*BufferedWriterCloser)

Inside the parens, we put the type we want to convert to. We can use the comma-ok, o if the type assertion fails, the app does not panic:

r, ok := w.(io.Reader)
if ok {
  fmt.Println(r)
} else {
  fmt.println("Convertion failed")
}

Now about empty interfaces, it’s just a empty interface define on the fly, with no methods assign to it. var myObj interface{} = newBufferedWriterCloser()

The nice thing is that evertyhing can be casted to the empty interface. This can be usefull when working with a lot of thing that are not type compatible.

But in this case, myObj has no methods so we cannot do anything. You can try to typecast the variable:

if wc, ok := myObj.(WriterCloser); ok {}

We’ve tried to typecast myObj with the comma_ok syntax. If return an ok, enter in the if statement.

So empty interfaces are useful as a middle step. You first declare it, and then you choose what to do with it.

Empty interfaces are often used with switch cases:

var i interface{} = 0
switch i.(type) {
  case int:
    fmt.Println("i is an integer")
  case string:
    fmt.Println("i is aa string")
  default:
    fmt.Println("I don't know what i is")
}

Now about pointers and interfaces. When implementing an interface, if one of your methods has a pointer receiver, like this:

type WriterCloser interface {
  Writer
  Closer
}

type myWriterCloser struct {}

func (mwc *myWriterCloser) Write(data []byte) (int error) {
  return 0, nil
}

You have to implement the interface as a pointer: var wc WriterCloser = &myWriterCloser{}

Best practices for using interfaces

Resume of interfaces, because it’s really hard man!

First define the interface. It is a type, with the name of the interface and the keyword interface. Inside there are the methods of the interface, the behaviour of that interface:

type Writter interface {
  Write([]byte) (int, error)
}

Then you implement the interface by implicit defining an interface method into a type:

type ConsoleWriter struct{}

func (cw ConsoleWriter) Write(data []byte) (int, error) {
  n, err := fmt.Println(string(data))
  return n, err
}

Now you can use this type, with the methods of the interface:

func main() {
  var w Writer = ConsoleWriter{}
  w.Write([]byte("Hello Go!"))
}

Go Routines

Enable us to work with concurrency easily in Go apps.

func main() {
	go sayHello()
  time.Sleep(100 * time.Millisecond)
}

func sayHello() {
	fmt.Println("Hello World")
}

That go keyword in front of the function call will start a green thread and run the say hello in that thread.

In this example, the main func runs in it’s own goroutine already. So by starting another goroutine, we have to delay the exit process of the main, so the other goroutine can start and call our sayHello.

Most programming languages use OS (Operation System) threads. This means they use an individual call stack dedicated to the execution to the code. They tend to be very expansive, that’s why we have thread pooling and other stuffs. In Go this works a bit different.

Green thread means that, intead of using those heavy threads, we are using an abstraction called goroutine. Inside the Go runtime, we have a scheaduler that will math the goroutines with the OS threads available. We don’t have to deal with the lower level threads, just with the abstraction (goroutine) The benefit is that goroutines can start with very small stack spaces, so they are cheap to create and destroy.

We can have thousands or more goroutines running in an app, with no problem at all.

Another example, passing arguments into a goroutine. Although Go has the concept of Closures, it’s not good to pass an outer variable directly into the goroutine function. It’s better to use the following pattern:

func main() {
  var msg = "Hello"
  go func(msg String) {
    fmt.Println(msg)
  }(msg)
  msg = "Goodbye"
  time.Sleep(100 * time.Millisencod)
}

// RESULT
Hello

Now, we are passing the msg as an argument, so passing by value. That means the goroutine function will no depend on the outer variable anymore. So it will print “Hello”, and will not be change and print “Goodbye”

These examples ae not good because they use the time.Sleep, which is bad practice. An alternative is to use the sync.WaitGroup{}, they will sync your goroutines.

import (
	"fmt"
	"sync"
)

var wg = sync.WaitGroup{}

func main() {
	var msg = "Hello"
	wg.Add(1)
	go func(msg string) {
		fmt.Println(msg)
		wg.Done()
	}(msg)
	msg = "Goodbye"
	wg.Wait()
}

The WaitGroup in wg starts at 0. The wg.Add(1) indicates we have one more goroutine to run. The wg.Wait() waits for the goroutines to be executed all, waits for the WaitGroup be 0 again so it can exit. The wg.Done() decrements the WaitGroup by -1, so it indicates the goroutine is done.

How about when launching multiple goroutines together, that depends on one another? Take this code for example:

var wg = sync.WaitGroup{}
var counter = 0

func main() {
	for i := 0; i < 10; i++ {
		wg.Add(2)
		go sayHello()
		go increment()
	}
	wg.Wait()
}

func sayHello() {
	fmt.Printf("Hello #%v\n", counter)
	wg.Done()
}

func increment() {
	counter++
	wg.Done()
}

We should expect the result to be predictable, by printing “Hello #1” and so on. But in this case, the goroutines are in race condition, rying to finish the job as soon as possible. We have to somehow sync them.

We could’ve used WaitGroup again to this issue, but let’s taks about another approach with sync.RWMutex. Mutex is basically a lock to your app. It is either locker or unlocked.

If the app is locked and someone tries to manipulate that value, it has to wait until it gets unlocked. We can then, protect our code so that only one entity can manipulate the data at a single time. It protect from race conditions.

RXMutex means ReadWrite Mutex. It means everybody can read the data but only one can modify (write) at a single time. And if something is reading the data, we can’t write to it. So we have a infinite number of readers and only one writer. The writer has to wait until every reader reads the data, and only then it will be able to write. When writing to the data, it locks the data and no one can read or write to it, until it unlocks.

var wg = sync.WaitGroup{}
var counter = 0
var m = sync.RWMutex{}

func main() {
	for i := 0; i < 10; i++ {
		wg.Add(2)
    m.RLock()
		go sayHello()
    m.Lock()
		go increment()
	}
	wg.Wait()
}

func sayHello() {
	fmt.Printf("Hello #%v\n", counter)
  m.RUnlock()
	wg.Done()
}

func increment() {
	counter++
  m.Unlock()
	wg.Done()
}

So we are using the m.RLock() to lock the read in the sayHello func. So after it prints the phrase, we unlock the read with m.RUnlock(). Then, in the icnrement function we are modifiying the data so we have to call m.Lock before, then we increment the value (counter++) and the call m.Unlock().

Best practices with GoRoutines

Channels

The majoroty of languages out there were designed with single processing core in mind. So it was hard to do concurrency and paralellism. Go is born in multiprocessing world.

Channels can be used to pass data between goroutines, and avoid race conditions and memory share problems.

Almost everytime you work with channels, it will be in the context of goroutines.

var wg = sync.WaitGroup{}

func main() {
  ch := make(chan int)
  wg.Add(2)
  go fun() {
		i := <- ch
		fmt.Println(i)
		wg.Done()
	}()
	go func() {
		ch <- 42
		wg.Done()
	}()
	wg.Wait()
}

We created the WaitGroup in order to sync the goroutines, to make sure our main goroutine waits until other routines finish. And then we will use channels to syncronize the data flow between them

Channels are created with the make function. First we define the chan keyword and then the data type that will flow through the channels. You can only pass data from the type you defined.

We defined 2 item to the WaitGroup, so 2 goroutines will be created. The first goroutine will receive data from the channel. The second will send data.

So this syntax ch <- 42 it’s passing the data 42 into the channel. Think like the arrow <- is pointing to where the data should go, so 42 should go into the channel.

The same way, if we want to get data from the channel: i := <- ch

We are passing a copy of the data to the channel, so if you pass the data and the modify the data, the modification will not happen inside the channel:

go func() {
  i := 42
  ch <- i
  i := 17
  wg.Done()
}()

// The goroutine receiver will print out 42!

Another thing to keep in mind is:

ch := make(chan int)
go func() {
  i := <- ch
  fmt.Println(i)
  wg.Done()
}()

for j:= 0; j < 5; j++ {
  wg.Add(2)

  go func() {
    ch <- 42
    wg.Done()
  }()
}

wg.Wait()

In the example above, we have one channel, only one receiver channel and 5 sender channels (inside the for loop) This will give us a deadlock error. Because the goroutine will send data (42) into the channel for the first time, and the receiver will listen one time and then close (wg.Done()). Then, the secondo time the receiver try to send data into the channel, nobody will listen to that, since there was only one recevier and it is already done. So the takeway is: when sending data into the channel, something has to listen to that data.

Channels can be receiver AND senders, like the example below:

go func() {
  i := <- ch
  fmt.Println(i)
  ch <- 27
  wg.Done()
}()

go func() {
  ch <- 42
  fmt.Println(<-ch)
  wg.Done()
}()

Send the 42 into the channel, the upper function reads it, and then pass 2 into the channel. Then the bottom function reads it.

We can specify the goroutines to be only senders or receivers, by passing arguments into the function:

ch := make(chan int)

go func(ch <-chan int) {
  i := <- ch
  fmt.Println(i)
  wg.Done()
}(ch)

go func(ch chan <- int) {
  ch <- 42
  wg.Done()
}(ch)

ch <-chan int it means data is flowing out of the channel. (receiving) ch chan <- int means we are sending data into the channel (chan) (sending)

Before we ran into the issue of only one receiver and 5 senders, which caused the deadlock problem. We can solve that by using buffers, passing a second parameter when creating a channel: ch := make(chan int, 50)

Buffers are used when your sender or receiver needs more time to process the data. For example, when a sender has too much information to send, the receiver has to deal with that somehow. That’s when we need buffers to put the data while the receiver process the incoming data.

A buffer will block the channel, until the receiving (or sender) is able to handle the data.

The best way to process the big incoming data with buffers is with a looping construct, using range, where we range the channel:

var wg = sync.WaitGroup{}

func main() {
  ch := make(chan int, 50)
  wg.Add(2)
  go func(ch <-chan int) {
    for i := range ch {
      fmt.Println(i)
    }
    wg.Done()
  }(ch)
  go func(ch chan<- int) {
    ch <- 42
    ch <- 27
    wg.Done()
  }(ch)
  wg.Wait()
}

When you range a channel, the first value it’s actually the value. If you range a slice for example, the first value would be the index.

Now if we run this code, we print the 2 values but we still deadlock the application. But the deadlock now is in the receiver, because it doesn’t know how to exit, it still waits for more data to process. So to handle that we can call the close(ch) in the sender, right after the second message ch <- 27, to the app knows we are done with the channel and can close it.

go func(ch chan<- int) {
  ch <- 42
  ch <- 27
  close(ch)
  wg.Done()
}(ch)

Once you close the channel, you can’t reopen that, and you can’t send any more messages there.

On the receive side, you can use a regular for loop without the range, and close the channel manually using the comma-okay syntax:

go func(ch <- chan int) {
  for {
    if i, ok := <- ch; ok {
      fmt.Println(i)
    } else {
      break
    }
  }
  wg.Done()
}

Above, we break the loop if ok is false.

Select Statements

We should always know how the goroutine will shutdown. We can use defer to close the goroutine and channel, but we will use another alternative called select statements.

tip: var doneCh = make(chan struct{})

struct{} has zero allocation of memory. It is used just to sign that we send something through the channel, without actually passing any data. It calls signal channel, and it’s very common. Instead of passing a bool into the channel to know if it’s working, just use this syntax.

To use the select statement to close the channel:

package main

import (
  "fmt"
  "time"
)
const (
  logInfo = "INFO"
  logWarning = "WARNING"
  logError = "ERROR"
)

type logEntry struct {
  time time.Time
  severity string
  message string
}

var logCh = make(chan logEntry, 50)
var doneCh = make(chan struct{})

func main() {
  go logger()
  logCh <- logEntry{time.Now(), logInfo, "App is starting"}

  logCh <- logEntry{time.Now(), logInfo, "App is shutting down"}
  time.Sleep(100 * time.Millisecond)
  doneCh <- struct{}{}
}

func logger() {
  for {
    select {
      case entry := <- logCh:
        fmt.Printf("%v - [%v]%v\n", entry.time.Format("2006-01-02T15:04:05"), entry.severity, entry.message)
      case <- doneCh:
        break
    }
  }
}

The select statement is going to block until a message arrive in one of the channels it is listening for (in this case, logCh and doneCh)

At the end of the main function, we passed a message to our doneCh, just a signal without data. struct{}{} is defining the struct with no fields (struct{}) and initializing that struct ({})

This is a common case when you have to monitor the channels and need the channel to terminate somehow.

You can have a default case in the select statement, but the it will be unblocked since everything that is not in the case statements will be in the default. So if you wanna block the select statement and only run if a case is matched (in case there is something in the channels), don’t use the default.