Expand/Shrink

Go cheatsheet

Installing Go
https://golang.org/doc/install
$ go version

Go program
package main
//import "fmt" or more often
import (
  "fmt"
  r "math/rand"
)
func main() {
  fmt.Println("Hello",r.Int())
}

Build & Run
$ ### RUN ###
$ go run .
$ ### VET & BUILD & RUN ###
$ go vet hello.go
$ go build hello.go
$ ./hello
$ ### INSTALL & RUN ###
$ go install hello.go
$ $GOBIN/hello

Comments
// line comment
/* multi-line, non-nestable */
Variables & Constants
// declaration
var msg string
msg = "Hello"
// short with type inference
// (nb only inside a function)
msg := "Hello"
// constants [opt ()]
// num/char/string/bool only
const Pi = 3.14159
ip, port := "127.0.0.1", "8080"
fmt.Println(ip + ":" + port)

Types
str := "Hello" // string
str := `Multiline string`
num := 3 // int
num := 3. // float64
num := 3 + 4i // complex128
var c rune = 'l' // UTF-8
num := byte('A') // byte/uint8
fmt.Printf("%T\n", i) // print
s := reflect.TypeOf(i).String()
type Weight float64 // custom
w := Weight(70) // conversion

Pointers
var pi *int = &i // point to i
p := &i // point to i
*p = *p * 2 // dereferencing
ps.x == (*ps).x // equivalent

Resources
https://tour.golang.org/
https://github.com/golang/go/wiki
https://repl.it/languages/go
https://awesome-go.com/

Arrays
var a [5]int // fixed size
a[0] = 3 // assignment
a := [...]int{1,3:2,3,6:-1}
var a [2][3]int
pa := *[32]byte{}

Slices
var s []int // dynamic size
s := []int {1,2,3}
s := []byte("Hello")
s := make([]string, 3)
s = append(s, "d", "e")
s = append(s, s2...) // (nb ... rqd)
c := make([]string, len(s))
copy(dst, src)
x := s[2:5] // elem. 2,3,4
y := s[:5] // elem. < 5

Maps
m := make(map[string]int)
m["key1"] = 42
fmt.Println("map: ", m)
m := map[string]int{"foo": 1,
"bar": 2} // initialize
v := m["key1"]
_, contains := m["key2"]
length := len(m)
delete(m, "key1")

Loops
for i := 0; i < 10; i++ {/**/}
for i <= 3 { i = i + 1 }
for {/**/ continue /**/ break}

Ranges
s := []string{"a", "b", "c"}
for idx, val := range s {/**/}
for i, rune := range str {} 
m := map[string]int{"a": 1}
for k, v := range m {/**/}

Conditionals
if d == "Sun" || d == "Sat" {
} else if d == "Mon" && foo() {
} else if _,err:=f(); err!=nil {
} else {/**/}

Switches
switch time.Now().Weekday() {
  case 0: fallthrough
  case 1: fmt.Println("Weekend")
  default: fmt.Println("Workday")
}
switch {
  case hour<12: fmt.Println("am")
  default:      fmt.Println("pm")
}

Defer
file, err := os.Create("foo")
if err != nil { return err }
defer func() { file.Close() }()
//NB: defer funcs must use named returns
//     to change their parent’s results

Functions
func add(a int, b int) float64 {
  return float64(a + b)
}
func tuple() (int, int) {
  return 4, 2
}
x, y := tuple()
func fvar(nums ...int) {/**/}

Closures & Lambdas
func adder() func(int) int {
  sum := 0
  return func(x int) int {
            sum += x
            return sum
         }
}
myLambda := func() bool {/**/}

Errors
import "errors" // (or "fmt" as below)
function err() (int,error) {
  return 0,errors.New("an error")
//return 0,fmt.Errorf("ch '%c'", c)
}

Structs & Methods
type Person struct {
  name string
  age int
}
func (p *Person) Aging(y int) {
  p.age = p.age + y
}
p := Person{name: "Bob", age: 4}
p.age = 30
p.Aging(1)

Interfaces
type geometry interface {
  area() float64
  perim() float64
}
func (r rect) area() float64 {}
func (r rect) perim() float64 {}
func measure(g geometry) {}
r := rect{width: 2, height: 4}
measure(r)

Concurrency
func f(c chan int) {}
c := make(chan int[, bufferLen])
go func() { fmt.Println(<-c) }()
c <- 2 // send 2 to c
x, y := <-c, <-c // recv from c
close(c) // close chan
select { case c <- x: /**/
         case <-quit: return }

Sync
var mu sync.Mutex // sync.Once
// .Lock();.Unlock();once.Do(f)
var wg sync.WaitGroup
// .Add(int);.Done();.Wait()
Runes
import ( "strings"; "sort" )
// runes implements sort.Interface for []rune
type runes []rune
func (r runes) Len() int { return len(r) }
func (r runes) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
func (r runes) Less(i, j int) bool { return r[i] < r[j] }

func munge(s string) string {
    rs := runes(strings.ToLower(s))
    sort.Sort(rs)
    return string(rs)
}

Favour f() (res any, ok bool) {}
  over f() (res any, e error) {}.
func sum(a []int) (res int) {
    for _, v := range a { res += v }
    return res
}
func min(a, b int) int {
    if a < b { b = a }
    return b
}
// (untested)
func reverse(s []int) []int {
    j := len(s)-1
//  for i := 0; i < len(s)/2; i += 1 {
    for i := 0; i < j; i += 1 {
        s[i], s[j] = s[j], s[i]
        j -= 1
    }
    return s
}
func sort(s []int) {
    for i := 0; i < len(s)-1; i++ {
        for j := i + 1; j < len(s); j++ {
            if s[i] < s[j] {
                s[i], s[j] = s[j], s[i]
            }
        }
    }
}

//custom_sorting.go
package main

import (
    "fmt"
    "sort"
)

type ByLength []string

func (s ByLength) Len() int {
    return len(s)
}

func (s ByLength) Swap(i, j int) {
    s[i], s[j] = s[j], s[i]
}

func (s ByLength) Less(i, j int) bool {
    return len(s[i]) < len(s[j])
}

func main() {
    words := []string{"cloud", "atom", "sea", "by", "forest", "maintenance"}
    sort.Sort(ByLength(words))
    fmt.Println(words)
}
sort.Ints(), sort.Strings(): in-situ, or for reverse (each using two interfaces):
sort.Sort(sort.Reverse(sort.IntSlice(vals)))
sort.Sort(sort.Reverse(sort.StringSlice(words)))
also: sort.IntsAreSorted() and sort.StringsAreSorted()
sort.Slice(words, func(i1, i2 int) bool { return len(words[i1]) < len(words[i2]) })
 
// Adds thousand separators to an integer.
func commatize(i int, thou string) string {
    // convert eg 1000 to "1,000", where the ',' is from the thou arg
    if (i < 1000) { return fmt.Sprintf("%d",i)}
    return fmt.Sprintf("%s%s%03d",commatize(i/1000,thou),thou,i%1000)
}
pounds := commatize(cents/100, ",")
pence := fmt.Sprintf("%s%02d", ".", cents%100)
amount := pounds + pence
 
var s string
runes := []rune(s) // equivalent to utf8_to_utf32()