# 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()