Go

Google created a programming language. What's it like?

Overview

Go is a systems programming language that first appeared in 2009. Most notably:

For a great introduction and overview of Go, see the Go Programming Language FAQ. One of the answers from the FAQ gives the rationale for the language:

Go is an attempt to combine the ease of programming of an interpreted, dynamically typed language with the efficiency and safety of a statically typed, compiled language. It also aims to be modern, with support for networked and multicore computing. Finally, it is intended to be fast: it should take at most a few seconds to build a large executable on a single computer. To meet these goals required addressing a number of linguistic issues: an expressive but lightweight type system; concurrency and garbage collection; rigid dependency specification; and so on. These cannot be addressed well by libraries or tools; a new language was called for.

Getting Started

Let's start with Hello, world:

hello.go
package main

import "fmt"

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

To build and run:

$ go run hello.go
Hello, world

or you can do it the long way:

$ go build hello.go && ./hello
Hello, world

And another little script:

fib.go
package main

import "fmt"
import "os"
import "strconv"

func main() {
    n, error := strconv.Atoi(os.Args[1])
    if error != nil {
        fmt.Println("A single integer commandline argument is required")
    } else {
        a, b := 0, 1
        for b <= n {
            fmt.Println(b)
            a, b = b, a + b
        }
    }
}
$ go run fib.go 100
1
1
2
3
5
8
13
21
34
55
89
$ go run fib.go dog
A single integer commandline argument is required
Exercise: The program crashes with an error if run without any command arguments. Fix it.

And another:

triple.go
package main

import "fmt"

func main() {
    for c := 1; c <= 100; c++ {
        for b := 1; b <= c; b++ {
            for a := 1; a <= b; a++ {
                if a * a + b * b == c * c {
                    fmt.Printf("(%d,%d,%d)\n", a, b, c)
                }
            }
        }
    }
}

Now, here are a few more sample programs.

Learning Go

You should spend the time to take the interactive tour at gloang.org. It is very good.

Also, go through the excellent Go By Example. It isn't interactive like Google's Tour of Go; however, the annotations beside the example code are really nice.

You can also experiment a little using the Go Playground. There's no actual REPL for Go, but things compile so fast it probably doesn't matter too much.

Useful Links

Language Highlights

Using Standard Packages

Go programs must run in a package (they start in main) and there are a bunch of standard packages that you can import from.

Please browse the list of standard packages to see what's available.

A small example:

misc.go
package main

import (
    "fmt"
    "strings"
    "time"
    "math/rand"
)

func main() {
    fmt.Printf("%q\n", strings.Split("a:bcd:ef", ":"))
    r := rand.New(rand.NewSource(time.Now().UnixNano()))
    fmt.Println(r.Int31())
}

Writing Functions

When writing function signatures supply the argument and argument type(s), and the return type(s). You can name the return value(s) too. Variadic functions are supported, too:

example-functions.go
package main

import "fmt"

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

func divide(x, y int) int {
    return x / y
}

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

func divmod(x, y int) (quo, rem int) {
    quo = x / y
    rem = x % y
    return
}

func sumOfFloats(a ...float64) float64 {
    total := 0.0
    for _, x := range a  {
        total += x
    }
    return total
}

func main() {
    fmt.Println(add(1, 2), divide(33, 10))
    one, two := swap("ho", "hi")
    three, four := divmod(97, 25)
    fmt.Println(one, two, three, four)
    fmt.Println(sumOfFloats(8, 4.3, -2, 11.9))
}

Variables

Variables are declared with var. There is some degree of type inference. There is a default initial value for each type. Inside a function, a short variable declaration is allowed (but never outside a function).

vars.go
package main

import "fmt"

var x int = 10
var y int                      // value is 0
var z = 12                     // type inferred to be int
var a, b, c bool               // multiple vars declared at once
var p, q float64 = 8.9, 2.3    // multiple vars with initializers

var (
    message = "O noes"
    start complex128
)

func main() {
    var s rune = '$'           // nothing special here
    t := "hello"               // short var declaration, same as var t string = "hello"

    fmt.Println(x, y, z, a, b, c, p, q, s, t, message, start)
}

Conditionals

TODO - If and Switch

Loops

Write loops with the for statement. Learn by example:

Note that just as with the if statement, variables declared at the top of the statement, before the block, are local to the block.

Pointers

Just like in C, people:

simple-pointers.go
package main

import "fmt"

func triple(x int) {
    x *= 3                      // Yep, this is completely useless
}

func reallyTriple(x *int) {
    *x *= 3                     // Changes the referent of the argument
}

func main() {
    x := 3
    y := &x                     // Perfectly okay to point to a local variable
    triple(x)                   // x ain't gonna change
    fmt.Println(x)              // Prints 3
    reallyTriple(y)             // You should draw a picture of what's going on
    fmt.Println(x)              // Yep, prints 9
}

Structs

TODO

new

TODO

Slices and Arrays

TODO

Maps

TODO

Functions as Values

TODO - Closures too

Methods

A method is a function with a receiver. Generally the receiver is a pointer but doesn't have to be. By making it a pointer you allow the method to be a mutator, and you don't incur cost of a copy. TODO

Interfaces

An interface is a collection of method signatures. You don't have to say that a type impements an interface, the compile will check that all the methods are implemented when you try to assign (or pass) an object to a variable that is given an interface for a type.

shapes.go
package main

import (
    "fmt"
    "math"
)

type Shape interface {
    perimeter() float64
    area() float64
}

type Circle struct {
    radius float64
}

func (c Circle) perimeter() float64 {
    return 2.0 * math.Pi * c.radius
}

func (c Circle) area() float64 {
    return math.Pi * c.radius * c.radius
}

type Rectangle struct {
    length, width float64
}

func (r Rectangle) perimeter() float64 {
    return 2.0 * (r.width + r.length)
}

func (r Rectangle) area() float64 {
    return r.width * r.length
}

func showDetails(s Shape) {
    fmt.Printf("%T perimeter is %g and area is %g\n", s, s.perimeter(), s.area())
}

func main() {
    showDetails(Rectangle{5.5, 20.3})
    showDetails(Circle{10})
}
$ go run shapes.go
main.Rectangle perimeter is 51.6 and area is 111.65
main.Circle perimeter is 62.83185307179586 and area is 314.1592653589793

Errors

TODO

Goroutines

TODO

Channels

Unit Testing

No asserts, strangely enough. Anyway, here is a pacakge to test:

stats.go
package stats

import "errors"

func Average(a []float64) (float64, error) {
    if len(a) == 0 {
        return 0, errors.New("No average for empty collection")
    }
    total := 0.0
    for _, x := range a {
        total += x
    }
    return total / float64(len(a)), nil
}

And here's the test.

stats_test.go
package stats

import "testing"

func TestAverage(t *testing.T) {
    average, error := Average([]float64{10.0, 1.0, 4.0})
    if average != 5.0 && error != nil {
        t.Errorf("Average of [10, 1, 4] should be 5")
    }
    _, error = Average([]float64{})
    if error == nil {
        t.Errorf("Average of empty slice should return an error")
    }
}

The code and the test should be the only two things in the directory. Then do:

$ go test
PASS
ok      _/Users/ray/w/code/go/stats 0.040s

This works, and is good enough for school, but in general, testing should be part of building your applications according to the standard Go project layout, which you'll learn about in the video in the next section.

Writing Large Go Applications

Here is how you can build an app using your own packages.

Reference Material

Here's some interesting technical items from the Go Programming Language Specification: