What?⌗

  • statically typed (w/ type inference)
  • compiled (statically linked)
  • memory safety, garbage collection
  • built in dependency management
  • concurrency:
    • goroutines (~coroutines/threads)
    • channels
    • select (for channels)
  • interfaces for “virtual inheritance”, type embedding
  • standardized formatting (gofmt)
  • multiple implementations (gc, gccgo, gollvm, gopherjs, …)

Why?⌗

  • mascot: gopher
  • started by Google in 2007
  • focusing on multicored/networked problems
  • efficient (like C)
  • readable & usable (like Python)
  • high performance networking & multiprocessing
  • primary motivation: dislike of C++ :)

How?⌗

Play with it: Go Playground

Flow control⌗

for⌗

Classic:

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

While:

sum := 0
for sum < 100 {
    sum += 1
}

Endless loop:

for {
    // neverending story
}

if⌗

if i < 10 {
    // i < 10
} else {
    // i >= 10
}

W/ short statement:

if s := math.Sin(f); s < .5 {
    return s
}
// s isn't defined here

switch⌗

Basically many ifs, no silly breaks and such:

switch os := runtime.GOOS; os {
case "darwin":
    // MacOS
case "linux":
    // Linux
default:
    // anything else
}

defer⌗

Defers execution until the function returns (~finally).

func x(i) {
    defer fmt.Println("x exited")

    if i > 10 {
        return "big"
    }
    return "small"
}

Deferred functions are stacked, called in a reverse order.

Types⌗

No variable is uninitialized.

Basic types, zero values⌗

  • bool (false)
  • numbers (byte, uint8, int16, float32, complex128, …) (0)
  • string ("")
  • rune (int32 - unicode character) (’')

Inference:

var i int // i == 0
j := 16 // j is int
k := i + j // k is 16, int

Pointers, references⌗

Without pointer arithmetic:

i := 42
p = &i
*p = 21
fmt.Println(*p) // prints 21

Structs⌗

type Color struct {
    R, G, B int
    Alpha float32
}

c1 := Color{100, 200, 200, .5}
c.R = 200 // {200, 200, 200}

Arrays⌗

var a [2]int
a[0] = "Hello"
a[1] = "World"

nums := [4]int{1,2,3,4}

Slices⌗

~dynamic views of arrays

nums2 := nums[1:3] // {2, 3}, nums2 is a slice, not an array
nums2[0] := 5 // nums became {1,5,3,4}

nums3 := []int{5,4,3,2,1} // nums3 is a slice, the underlying array is hidder
  • length - current size of the view
  • capacity - the size of the underlying array
  • make() - create slice with the given length/capacity
  • append()- smart append, increases capacity when required
  • range - for iterating through iterables
nums4 := make([]int, 1, 2) // {0} with capacity of 2
nums4[:cap(num4)] // {0, 0}
append(nums4, 1, 2, 3) // {0, 0, 1, 2, 3}, no idea of capacity, maybe 8

for i, v := range nums4 {
    fmt.Printf("%d. %d\n", i, v)
}

Maps⌗

Nothing special, make can also used to create them.

var m1 map[string]int
m1["cica"] = 4
m1["kutya"] = 27


m2 := map[string]int{
    "cica": 5,
    "kutya": 28,
}

m3 := make(map[string]int)

// check if key is included
v1, ok := m1["egér"] // v1 == 0, ok == false

Functions⌗

… can be values too.

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

func applyWith2(x int, fn func(int, int) int) int {
    return fn(x, 2)
}

Error handling: return it!

func div(x, y int) (int, error) {
    if y == 0 {
        return 0, errors.New("Cannot divide by zero!")
    }
    return x / y, nil
}

Parameters are passed as value by default, so copyed on function call - but you can explicitly use pointers to avoid copying or to be able to modify the original object.

Methods⌗

Go does not have classes, but you can define methods on types - not just structs, but any type defined in the same package. They are basically functions, with a receiver argument.

type Color struct {
    R int `json:"red"` // example for tags
    G int `json:"green"`
    B int `json:"blue"`
}

func (c Color) Grayscale() Color {
    g := (c.R + c.G + c.B) / 3
    return Color{g, g, g}    
}

func (c *Color) Darken() { // can use pointers as well
    c.R = c.R / 2
    c.G = c.G / 2
    c.B = c.B / 2
}

type MyFloat float64

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

    return float64(f)
}

Interfaces⌗

Interface: a set of method signatures.

type Abser interface {
    Abs() float64
}

func PrintAbs(a Abser) {
    fmt.Println(a.Abs())
}

// PrintAbs(MyFloat(-12))

Implementation is implicit, MyFloat is an Abser, even if I defined the interface later (even in an other package).

Special empty interface: interface{}- all types implement it, ~Object.

Type assertion:

func PrintAbs(a Abser) {
    i, ok := a.(MyInt)
    if ok {
        // handle integer
    }

    f, ok := a.(MyFloat)
    if ok {
        // handle float
    }

    // OR

    switch v := i.(type) {
    case MyInt:
        // handle MyInt
    case MyFloat:
        // handle MyFloat
    default:
        // whatever
    }
}

Interface example: fmt.Stringer-> anything w/ aString()method

error is an interface too:

type error interface { // this is built in
    Error() string
}

type MyError struct {
    When time.Time
    What string
}

func (e *MyError) Error() string {
    return fmt.Sprintf("[%v] %s", e.When, e.What)
}