Go Cheatsheet

Table of Contents

Go is an open source programming language from Google that makes it easy to build simple, reliable, and efficient software.

Getting started

Hello world

package main

import "fmt"

func main() {
  message := greetMe("world")
  fmt.Println(message)
}

func greetMe(name string) string {
  return "Hello, " + name + "!"
}
$ go build

Or try it out in the Go repl, or A Tour of Go.

Variables

Variable declaration

var msg string
msg = "Hello"

Shortcut of above (Infers type)

msg := "Hello"

Constants

const Phi = 1.618

Constants can be character, string, boolean, or numeric values.

See: Constants

Basic types

Strings

str := "Hello"
str := `Multiline
string`

Strings are of type string.

Numbers

Typical types

num := 3          // int
num := 3.         // float64
num := 3 + 4i     // complex128
num := byte('a')  // byte (alias for uint8)

Other types

var u uint = 7        // uint (unsigned)
var p float32 = 22.7  // 32-bit float

Arrays

// var numbers [5]int
numbers := [...]int{0, 0, 0, 0, 0}

Arrays have a fixed size.

Slices

slice := []int{2, 3, 4}
slice := []byte("Hello")

Slices have a dynamic size, unlike arrays.

Pointers

func main () {
  b := *getPointer()
  fmt.Println("Value is", b)
}
func getPointer () (myPointer *int) {
  a := 234
  return &a
}

Pointers point to a memory location of a variable. Go is fully garbage-collected.

See: Pointers

Type conversions

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

See: Type conversions

Flow control

Conditional

if day == "sunday" || day == "saturday" {
  rest()
} else if day == "monday" && isTired() {
  groan()
} else {
  work()
}

See: If

Statements in if

if _, err := getResult(); err != nil {
  fmt.Println("Uh oh")
}

A condition in an if statement can be preceded with a statement before a ;.

See: If with a short statement

Switch

switch day {
  case "sunday":
    // cases don't "fall through" by default!
    fallthrough

  case "saturday":
    rest()

  default:
    work()
}

See: Switch

For loop

  for count := 0; count <= 10; count++ {
		fmt.Println("My counter is at", count)
	}

See: For loops

For-Range loop

  entry := []string{"Jack","John","Jones"}
  for i, val := range entry {
    fmt.Printf("At position %d, the character %s is present\n", i, val)
  }

See: For-Range loops

Functions

Lambdas

myfunc := func() bool {
  return x > 10000
}

Functions are first class objects.

Multiple return types

a, b := getMessage()
func getMessage() (a string, b string) {
  return "Hello", "World"
}

Named return values

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

By defining the return value names in the signature, a return (no args) will return variables with those names.

See: Named return values

Packages

Importing

import "fmt"
import "math/rand"
import (
  "fmt"        // gives fmt.Println
  "math/rand"  // gives rand.Intn
)

Both are the same.

See: Importing

Aliases

import r "math/rand"
r.Intn()

Exporting names

func Hello () {
  ···
}

Exported names begin with capital letters.

See: Exported names

Packages

package hello

Every package file has to start with package.

Concurrency

Goroutines

func main() {
  // A "channel"
  ch := make(chan string)

  // Start concurrent routines
  go push("Moe", ch)
  go push("Larry", ch)
  go push("Curly", ch)

  // Read 3 results
  // (Since our goroutines are concurrent,
  // the order isn't guaranteed!)
  fmt.Println(<-ch, <-ch, <-ch)
}
func push(name string, ch chan string) {
  msg := "Hey, " + name
  ch <- msg
}

Channels are concurrency-safe communication objects, used in goroutines.

See: Goroutines, Channels

Buffered channels

ch := make(chan int, 2)
ch <- 1
ch <- 2
ch <- 3
// fatal error:
// all goroutines are asleep - deadlock!

Buffered channels limit the amount of messages it can keep.

See: Buffered channels

Closing channels

Closes a channel

ch <- 1
ch <- 2
ch <- 3
close(ch)

Iterates across a channel until its closed

for i := range ch {
  ···
}

Closed if ok == false

v, ok := <- ch

See: Range and close

Error control

Defer

func main() {
  defer fmt.Println("Done")
  fmt.Println("Working...")
}

Defers running a function until the surrounding function returns. The arguments are evaluated immediately, but the function call is not ran until later.

See: Defer, panic and recover

Deferring functions

func main() {
  defer func() {
    fmt.Println("Done")
  }()
  fmt.Println("Working...")
}

Lambdas are better suited for defer blocks.

Structs

Defining

type Vertex struct {
  X int
  Y int
}
func main() {
  v := Vertex{1, 2}
  v.X = 4
  fmt.Println(v.X, v.Y)
}

See: Structs

Literals

v := Vertex{X: 1, Y: 2}
// Field names can be omitted
v := Vertex{1, 2}
// Y is implicit
v := Vertex{X: 1}

You can also put field names.

Pointers to structs

v := &Vertex{1, 2}
v.X = 2

Doing v.X is the same as doing (*v).X, when v is a pointer.

Methods

Receivers

type Vertex struct {
  X, Y float64
}
func (v Vertex) Abs() float64 {
  return math.Sqrt(v.X * v.X + v.Y * v.Y)
}
v: = Vertex{1, 2}
v.Abs()

There are no classes, but you can define functions with receivers.

See: Methods

Mutation

func (v *Vertex) Scale(f float64) {
  v.X = v.X * f
  v.Y = v.Y * f
}
v := Vertex{6, 12}
v.Scale(0.5)
// `v` is updated

By defining your receiver as a pointer (*Vertex), you can do mutations.

See: Pointer receivers

References