Programming November 08, 2014

Notes from learning Go – the basics

I recently decided to learn Go. As in Go the programming language, also known as golang. These are my notes from doing so. In the form of code.

Hello World

package main

//Here's a comment

import "fmt"

func main() {
    fmt.Println("Hello world")
}

Try it.

Variables and types

package main

import "fmt"

func main() {
    // Variables are declared using "var [name] [type]"
    var myVariable string
    myVariable = "I'm a string"
    myVariable += " and I was declared the long way"
    fmt.Println(myVariable)
    
    var length int = len(myVariable)
    fmt.Println("I'm this long:", length)

    // Using short variable declaration, omitting the var keyword
    mySecondVariable := "I'm also a string but I was declared the short way"
    fmt.Println(mySecondVariable)

    const constant = "I'm a constant with inferred type"
    fmt.Println(constant)

    var (
        var1 = "This is"
        var2 = "multiple"
        var3 = "variables"
    )

    fmt.Println(var1, var2, var3)
}

Try it.

If statements and loops

package main

import "fmt"

func main() {
    i := 1
    for i <= 5 {
        fmt.Println(i)
        i += 1
    }

    for i := 6; i <= 10; i++ {
        if i % 2 == 0 {
            fmt.Println(i, "even")
        } else if i % 3 == 0 {
            fmt.Println(i, "divisible by 3")
        } else {
            fmt.Println(i, "odd and not divisible by 3")
        }
    }
}

Try it.

Switch

package main

import "fmt"

func main() {
    i := 3

    switch i {
        case 1: fmt.Println("One")
        case 2: fmt.Println("Two")
        case 3: fmt.Println("Three")
        default: fmt.Println("Uhmn, not sure")
    }

    switch i%2 {
        case 0: fmt.Println("Even")
        default: fmt.Println("Odd")
    }
}

Try it.

Arrays

package main

import "fmt"

func main() {
    var myArray [5]string
    myArray[2] = "I'm the third item"
    fmt.Println(myArray)
    myArray[0] = "Woho, I'm the first item!"
    fmt.Println(myArray)
    fmt.Println("Array length:", len(myArray))

    var intArray [3]int
    fmt.Println("\"Empty\" int array:", intArray)

    intArray = [3]int{1, 2}
    fmt.Println("Integer array with the two first values set:", intArray)

    var messageParts = [3]string{
        "Hello ",
        "there",
        "!",
    }

    var message string
    for i := 0; i < len(messageParts); i++ {
        message += messageParts[i]
    }
    fmt.Println(message)

    // Usign the range keyword. The underscore tells the compiler that we don't need the value (index in this case)
    var secondMessage string
    for _, value := range messageParts {
        secondMessage += value
    }
    fmt.Println(secondMessage)

    for idx, _ := range messageParts {
        fmt.Println("Index:", idx)
    }
}

Try it.

Slices

package main

import "fmt"

func main() {
    var myEmptySlice []string
    fmt.Println(myEmptySlice)

    sliceAssociatedWithArray := make([]int, 5)
    fmt.Println(sliceAssociatedWithArray)

    array := [5]int{1, 2, 3, 4, 5}
    middleSlice := array[1:4]
    fmt.Println(middleSlice)
    
    array[2] = 42
    fmt.Println(middleSlice)

    middleSlice[0] = 41
    fmt.Println(array)

    messageSlice := []string{"hello", "there"}
    messageSlice = append(messageSlice, "how", "are", "you")
    fmt.Println(messageSlice)

    helloOnlySlice := make([]string, 2)
    copy(helloOnlySlice, messageSlice)
    fmt.Println(helloOnlySlice)
}

Try it.

Maps

package main

import "fmt"

func main() {
    var myMap map[string]string
    myMap = make(map[string]string)

    myMap["hello"] = "hej"
    fmt.Println(myMap)
    fmt.Println(len(myMap))
    fmt.Println(myMap["hello"])

    delete(myMap, "hello")
    fmt.Println(myMap)
    fmt.Println(len(myMap))
    fmt.Println(myMap["hello"])

    // Maps, no matter if they have been initialized or not, return the
    // zero value for the type if they key doesn't have a value
    var ints map[string]int
    fmt.Println(ints["nothing"]) // Outputs 0
    // Accessing an element can return two values where the second is
    // the result of the lookup
    value, exists := ints["nothing"]
    fmt.Println(value) // Still 0
    fmt.Println(exists) // false

    // Short way of creating maps
    lengths := map[string]int {
        "hello": 5,
        "there": 5,
        "!": 1,
    }
    fmt.Println(lengths)

    // Iterating over elements
    for key, value := range lengths {
        fmt.Println(key)
        fmt.Println(value)
    }
}

Try it.

Functions

package main

import "fmt"

func main() {
    secondFunction()
    thirdFunction("Hello yourself!")
    fourthFunction("How", "are", "you", "today?")
    fmt.Println(fifthFunction())
    fmt.Println(sixthFunction())
    part1, part2 := seventhFunction()
    fmt.Println(part1, part2)
    fmt.Println(eightFunction()())
}

func secondFunction() {
    fmt.Println("Hello world!")
}

func thirdFunction(message string) {
    fmt.Println(message)
}

func fourthFunction(messages ...string) {
    for index, message := range messages {
        fmt.Print(message)
        if index < len(messages)-1 {
            fmt.Print(" ")
        } else {
            fmt.Println()
        }
    }
}

func fifthFunction() string {
    return "Hello world as return value"
}

func sixthFunction() (message string) {
    message = "Hello world as named return value"
    return message
}

func seventhFunction() (string, string) {
    return "Hello world", "from multiple return values"
}

func eightFunction() func() string {
    message := "Hello world from closure"
    return func() string {
        return message;
    }
}

Try it.

Pointers

package main

import "fmt"

func main() {
    message := "I'm the original, and best"

    modifier1(message)
    fmt.Println(message) // "I'm the original, and best"

    // The & operator finds the address for a variable, meaning that &message returns a *string
    modifier2(&message)
    fmt.Println(message) // "modifier2 was here"

    secondMessage := new(string) // the new operatore can be used to create pointers
    modifier2(secondMessage)
    fmt.Println(*secondMessage) // "modifier2 was here"
}

func modifier1(message string) {
    message = "modifier1 was here"
}

func modifier2(message *string) {
    *message = "modifier2 was here"
}

Try it.

Structs

package main

import "fmt"

func main() {
    rect := Rectangle{width: 10, height: 5}
    fmt.Println("Height:", rect.height, "Width:", rect.width)
    fmt.Println("Area:", area(rect))
}

type Rectangle struct {
    width, height int
}

func area(rect Rectangle) int {
    return rect.width*rect.height
}

Try it.

Methods

package main

import "fmt"

func main() {
    rect := Rectangle{width: 10, height: 5}
    fmt.Println("Area:", rect.area())
}

type Rectangle struct {
    width, height int
}

func (rect Rectangle) area() int {
    return rect.width*rect.height
}

Try it.

Embedding

package main

import "fmt"

func main() {
    bird := Bird{}
    bird.Animal.Eat()
    bird.Eat()
    bird.Fly()
}

type Animal struct {
}

func (animal *Animal) Eat() {
    fmt.Println("I'm eating")
}

type Bird struct {
    Animal
}

func (bird *Bird) Fly() {
    fmt.Println("I'm flying")
}

Try it.

Defer

package main

import "fmt"

func main() {
    defer first()
    second()
}

func first() {
    fmt.Println("First function here")
}

func second() {
    fmt.Println("Second function here")
}

Try it.

Panic and Recover

package main

import "fmt"

func main() {
    defer func() {
        message := recover()
        fmt.Println(message)
    }()

    panic("Something is seriously wrong")
}

Try it.

PS. For updates about new posts, sites I find useful and the occasional rant you can follow me on Twitter. You are also most welcome to subscribe to the RSS-feed.

Joel Abrahamsson

Joel Abrahamsson

I'm a passionate web developer and systems architect living in Stockholm, Sweden. I work as CTO for a large media site and enjoy developing with all technologies, especially .NET, Node.js, and ElasticSearch. Read more

Comments

comments powered by Disqus

More about Programming