Go Notes
Table of Contents
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 abovesha256sum 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
- Typically you will set
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 namedmain.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 download the SDK into the
- This will now make the beta available on your system as
go1.18beta2
. Use this as you would thego
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
andV
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 ofint64
andfloat64
, 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) } }
Bouncing DVD Logo w/ go-sdl2
This is a simple example that shows using go-sdl2 to render a bouncing DVD logo. This assumes that there is a ttf font in the root of the module named "Hack-Regular.ttf"
package main import ( "fmt" "os" "github.com/veandco/go-sdl2/sdl" "github.com/veandco/go-sdl2/ttf" ) const ( width = 640 height = 480 size = 100 fontPath = "Hack-Regular.ttf" fontSize = 48 ) func main() { if err := sdl.Init(sdl.INIT_EVERYTHING); err != nil { fmt.Fprintf(os.Stderr, "%s\n", err) os.Exit(1) } defer sdl.Quit() if err := ttf.Init(); err != nil { fmt.Fprintf(os.Stderr, "%s\n", err) os.Exit(1) } defer ttf.Quit() window, err := sdl.CreateWindow( "DVD Logo", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, width, height, sdl.WINDOW_SHOWN|sdl.WINDOW_ALLOW_HIGHDPI|sdl.WINDOW_RESIZABLE) if err != nil { fmt.Fprintf(os.Stderr, "%s\n", err) os.Exit(1) } defer window.Destroy() window.SetMinimumSize(width, height) renderer, err := sdl.CreateRenderer(window, -1, sdl.RENDERER_ACCELERATED) if err != nil { fmt.Fprintf(os.Stderr, "%s\n", err) os.Exit(1) } defer renderer.Destroy() renderer.SetLogicalSize(width, height) renderer.SetIntegerScale(true) font, err := ttf.OpenFont(fontPath, fontSize) if err != nil { fmt.Fprintf(os.Stderr, "%s\n", err) os.Exit(1) } defer font.Close() running := true var x int32 = 73 xDir := 1 var y int32 = 92 yDir := 1 for running { for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() { switch event.(type) { case *sdl.QuitEvent: running = false } } x += int32(xDir) y += int32(yDir) if x > (width-size) || x < 0 { xDir *= -1 } if y > (height-size) || y < 0 { yDir *= -1 } renderer.SetDrawColor(0, 0x19, 0, 255) renderer.Clear() renderer.SetDrawColor(255, 255, 255, 255) rect := sdl.Rect{X: x, Y: y, W: size, H: size} renderer.FillRect(&rect) t, err := font.RenderUTF8Blended("DVD", sdl.Color{R: 0, G: 0, B: 0, A: 255}) if err != nil { fmt.Fprintf(os.Stderr, "%s\n", err) os.Exit(1) } defer t.Free() tex, err := renderer.CreateTextureFromSurface(t) if err != nil { fmt.Fprintf(os.Stderr, "%s\n", err) os.Exit(1) } defer tex.Destroy() err = renderer.Copy( tex, nil, &sdl.Rect{ X: x + (size-t.W)/2, Y: y + (size-t.H)/2, W: t.W, H: t.H}) if err != nil { fmt.Fprintf(os.Stderr, "%s\n", err) os.Exit(1) } renderer.Present() sdl.Delay(16) } }
Recommended Packages
- tarm/serial - Great cross platform serial communication library