Go

Back to Languages/go

Go is a portable language, well catered for small tasks. In comparison to ruby, go has less overhead for simple low level tasks. Go is good for concurency.

Packages

Every go project is made up of packages. Prgrams start running in package main. The package name is same as last element of the import path (math/rand has package rand).

Individual statement: import "fmt". Factored import statement:

package main

import (
  "fmt" // formatted I/O package
  "math/rand"
)
func main() {
// ...
}

Exported names

A name is exported if it begins with a capital letter. Pi is exported from the math package.

When importing a package, only exported names are accessible. fmt.Println(math.Pi).

Functions

A function can return multiple results, comma delimited.

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

Return values can be named, and treated as variables in the return specification on the function.

func div10(sum int) (x, y int) {
  x = sum /10
  y = sum - x*10
  return // "naked" return, returns the current values of x and y
}
// div10(52) => 5 2

Variables

var statement declares a list of variables, type is last.

var c, python, java bool

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

An initializer assigns values: var i, j = 1, 2 (notice type can be omitted). := is the short assignment statement, used in place of var with implicit type declaration (only available within the scope of a func).

Variable Types

bool, string, int, int8, int16, int32, int64, float32, float64 (only specify size of ints in specific uses). Zero values are assigned when there is no explicit value given:

When declaring a variable without specifying type, type is inferred based on right side value.

A constant is decared like variables, but with const keyword instead of var. Cannot use := for constant declaration.

Pointers
Structs

collection of fields.

type Vertex struct {
  X int
  Y int
}
Arrays

[n]T is an array of n values of type T

Map

maps keys to values. Zero value of a map is nil. A nil map has no keys, keys cannot be added.

A map literal can be defined like var m = map[string]string { "hello": "world", "other": "string" }

Function Values

Functions are values too, and are able to be passed around like other values. func compute(fn func(int, int) int) int {}

Flow Control

For

for is the only looping construct. for i := 0; i < 10; i++ {}. This also works: for ; i < 10 ; {} (some optional fields). Also for i < 10 {}. for {} is infinite loop.

If

if i < 0 {} braces around condition are optional. if {} else {}. You can use the short assignment statement in the if condition to assign a test value to a variable: if v := math.Pow(x,n); v < lim { ... } where v is now accessible within the if block.

Switch

switch os := runtime.GOOS; os {
  case "darwin":
    fmt.Println("OS X")
  default:
    fmt.Printf("%s.", os)
}

Switch statement breaks after a case succeeds, read top to bottom.

Defer

defer fmt.Println("world") prints "world" when the func returns. Deferred function calls are pushed onto a stack.

Methods

Go has no classes. You can define methods on types. A method is a function with a special reciever argument.

func (v Vertex) Abs() float64 { // the method Abs has a reciever type Vertex
  return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
v := Vertex{3, 4}
v.Abs() // 5

A method is just a function that implicitly passes some reciever argument as the first parameter. Notice the difference between calling v.Abs() and Abs(v).

Interfaces

Interface type is a set of method signatures

type Abser interface {
  Abs() float64
}
type MyFloat float64
func (f MyFloat) Abs() float64 { //...

var a Abser
f := MyFloat(-math.Sqrt2)
a = f  // a MyFloat implements Abser
a.Abs() // runs f.Abs()

A type implements an interface by implementing its methods in the signature.

Deal with Interface Types

Type assertions provide access to an interface value's underlying concrete value. t, ok := i.(T) asserts the interface value i holds concrete type T, assigns it to t and returns a boolean to ok.

Type Switches permit several type assertions with a switch-case statement.

Concurrency

talk on concurrency. Concurrency and parallelism are not the same! Concurrency is a way to build things, a composition of independently executing things like functions (interacting processes). Parallelism is about execution, doing a lot of things at once. Concurrency is about structure, dealing with lots at once.

Analogy: Gophers are move books from one pile to another. Two Gophers can complete different tasks (one loads books, one moves them), this is called the concurrent composition of processes. It is only parallel if they work simultaneously.

The whole process can be redesigned, to have gophers do different tasks. This is improving performance by adding a concurrent procedure to the existing design. Each task does not necessarily have to run in parallel, but the parallelism of the whole process becomes a free variable to manipulate.

Goroutines

A goroutine is a thread managed by the Go runtime. go f(x, y, z) starts a gorountine that runs f.

Channels

Channels are typed conduit through which you send and recieve values with the channel operator <-. Allows communication between goroutines.

ch <- v    // sends v to channel ch
v := <-ch  // recieves ch and assign value to v

To create a channel, ch := make(chan int)

Channels by default, send and recieve, block until the other side is ready, allowing goroutines to synchronize without explicit locks or condition variables.

c := make(chan int) // makes a channel for integers
go sum(s[:len(s)/2], c) // 17
go sum(s[len(s)/2:], c) // -5
x, y := <-c, <-c // receive from c

fmt.Println(x, y, x+y) // -5 17 12

Channels can be buffered, with buffer length as the second argument to make to initialize a buffered channel: ch := make(chan string, 100). Sends to a buffered channel become blocked with the buffer is full. Recieves become blocked when the buffer is empty.

Range and Close

A sender can close(ch) a channel to indicate no more values will be sent. Recievers can test whether a channel has been cloesd by assigning a second parameter to the recieve expression. v, ok := <-ch, ok will be false if there are no more values to recieve.

for i := range c recieves values from channel until it's closed. Closing is only necessary when the reciever must be told there are no more values coming, as in a range loop.

Select

Like a switch, but decision is based on ability to communicate rather than equal values. Chooses which channel to recieve from.

select {
case c <- x:
  // ...
case <- quit:
  // ... where quit is some goroutine
default:
  // recieve from c would block
}

Assorted Go Functions

func make(Type, size IntegerType) Type