Adam Richardson's Site

Go Notes

Table of Contents

<2022-05-16 Mon>

Setup

Getting the latest release

  • Digital Ocean: How to install Go on Debian 10
  • The latest release of Go can be downloaded here
  • Copy the sha256 from the website to a local text file, echo "SHA_256_FROM_WEBSITE" > go_release_sha256.txt
  • Calculate the shaa256 of the download and ensure it matches the value in the text file made above
    • sha256sum go<VERSION>.linux-amd64.tar.gz
  • Extract the tarball with, tar -xvf go<VERSION>.linux-amd64.tar.gz
  • Change ownership of the go directory to the root user, sudo chown -R root:root ./go
  • Move the go folder to /usr/local, sudo mv go /usr/local
  • Update your path to include /usr/local/go/bin
    • Typically you will set GOROOT=/usr/local/go then update the path to have $GOROOT/bin

GOPATH

  • The default value for the $GOPATH environment variable is $HOME/go
  • Tools that are installed will be in $GOPATH/bin folder
  • It might be advantageous to add $GOPATH/bin to your $PATH environment variable

Hello World

  • The below code sample is a simple hello world program written in Go
  • It should go into its own project folder named hello-go and be named main.go
package main

import "fmt"

func main() {
        fmt.Printf("Hello, Go!\n")
}
  • To test out the Go install run go install hello-go
  • This should put a binary named hello-go in your path that should output "Hello, Go!" when run

Installing Beta Versions of Go

  • If you have go installed you can install a beta version using the go tool
  • For example: go install golang.org/dl/go1.18beta2@latest
  • Before you can run the beta version you need to run go1.18beta2 download
    • This will download the SDK into the $HOME/sdk folder
  • This will now make the beta available on your system as go1.18beta2. Use this as you would the go tool

Language Server

  • gopls is the official Go language server
  • You can install it with, go install golang.org/x/tools/gopls@latest
  • As far as I can tell the language server does not work in org babel source blocks

Emacs Org Babel Support

  • Emacs Package: ob-go
  • Manually edit org-babel-load-languages to include Go by adding it to the hash table (go . t)
  • This is an example using the args header argument, :args '("-count=5" "-msg=Hola")

Appending to a list

package main

import "fmt"

func main() {
        x := []int{}
        x = append(x, 10)
        fmt.Println(x)
}

Generics

Things you can do with generics that you cannot do with interfaces

  • The interface type only lets you define methods
  • This means that if you have a set of structs that all have a similar property you would need to define a method to access it generically
  • Using type constraints with structs allows you to define a generic type this is the union of all the other types

Simple Example

Non Generic Sum Functions

  • These sum functions only accept variables of a fixed type
  • These are here to contrast with the generic versions that can accept mulitple types
  • Note that the implementation of these functions is the exact same with the only difference being the type
func SumInts(m map[string]int64) int64 {
        var s int64
        for _, v := range m {
                s += v
        }
        return s
}

func SumFloats(m map[string]float64) float64 {
        var s float64
        for _, v := range m {
                s += v
        }

        return s
}

Generic Sum Function

  • In the square brackets below K and V are the names of the types used
  • comparable is a built in generic type that covers all types that support == and !=
  • Go requires map keys to be comparable
  • The V type is the union of int64 and float64, meaning only those types are allowed
func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V {
        var s V
        for _, v := range m {
                s += v
        }

        return s
}

Generics with Type Constraint

  • You can create a named type constraint using an interface
type Number interface {
        int64 | float64
}

func SumNumbers[K comparable, V Number](m map[K]V) V {
        var s V
        for _, v := range m {
                s += v
        }

        return s
}

Main

  • When calling a generic function you can specify the types being used in square brackets
  • For example, SumIntsOrFloats[string, int64](ints) is clearly stating the types used for the key and value
  • The square brackets can be omitted when the compiler is able to infer the types like the below example
func main() {
        ints := map[string]int64{
                "first": 34,
                "second": 12,
        }

        floats := map[string]float64{
                "first": 35.98,
                "second": 26.99,
        }

        fmt.Printf("Non-Generic Sums: %v and %v\n",
                SumInts(ints), SumFloats(floats))

        fmt.Printf("Generic Sums: %v and %v\n",
                SumIntsOrFloats(ints),
                SumIntsOrFloats(floats))

        fmt.Printf("Generic Sums with Constraint: %v and %v\n",
                SumNumbers(ints),
                SumNumbers(floats))
}

Putting it all together

package main

import "fmt"

func SumInts(m map[string]int64) int64 {
        var s int64
        for _, v := range m {
                s += v
        }
        return s
}

func SumFloats(m map[string]float64) float64 {
        var s float64
        for _, v := range m {
                s += v
        }

        return s
}

func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V {
        var s V
        for _, v := range m {
                s += v
        }

        return s
}

type Number interface {
        int64 | float64
}

func SumNumbers[K comparable, V Number](m map[K]V) V {
        var s V
        for _, v := range m {
                s += v
        }

        return s
}

func main() {
        ints := map[string]int64{
                "first": 34,
                "second": 12,
        }

        floats := map[string]float64{
                "first": 35.98,
                "second": 26.99,
        }

        fmt.Printf("Non-Generic Sums: %v and %v\n",
                SumInts(ints), SumFloats(floats))

        fmt.Printf("Generic Sums: %v and %v\n",
                SumIntsOrFloats(ints),
                SumIntsOrFloats(floats))

        fmt.Printf("Generic Sums with Constraint: %v and %v\n",
                SumNumbers(ints),
                SumNumbers(floats))
}

Using flag package

package main

import (
        "flag"
        "fmt"
)

func main() {
        var msg string
        var count int64

        flag.StringVar(&msg, "msg", "hello world", "message to show the user")
        flag.Int64Var(&count, "count", 1, "number of times to show the message")

        flag.Parse()

        for i := 0; i < int(count); i++ {
                fmt.Println(msg)
        }
}

Recommended Packages

  • tarm/serial - Great cross platform serial communication library