## Go Crash Course A quick 1 hour workshop on the basics of Go *John Nguyen*
## About Me - Studied Mechatronics Engineering at UWA - Worked in Mechanical and Process Controls Engineering - Started working at The Frontier Group in 2015 - Have worked with python, ruby/rails, nodejs, C#
## About Go [Go](https://golang.org/) is an open source programming language that makes it easy to build simple, reliable, and efficient software.
## Notable Companies Using Go - Google / Facebook / Yahoo - Rackspace / Digital Ocean / Heroku - Shopify / Booking.com / Medium - IBM / Comcast / Canonical - Square - SendGrid / Bitly - Docker - Dropbox
## Why Go? - Simple - Maintainable - Scales easily - Easily generated documentation - Fast - Robust tooling - Single, static binary - Fast compile times - Cross platform - Good community - Language level concurrency (no callback hell) - Useful error messages
## Why not Go? - No generics - No operator overloading - Inelegant - Ugly syntax - Poor dependency management - Garbage collector can not be modified easily - Verbose error handling
## Installation ### OSX ```bash brew update brew install go ``` ### Linux Download binary from [https://golang.org/dl/]() ```bash wget https://storage.googleapis.com/golang/go1.6.linux-amd64.tar.gz sudo tar -C /usr/local -xzf go1.6.linux-amd64.tar.gz ``` ### Web Visit [https://play.golang.org/]().
## Paths Add the following to your `.profile`. This will add the binaries to your PATH and also setup your GOPATH environment ```bash export PATH=$PATH:/usr/local/go/bin/:$HOME/go/bin export GOPATH=$HOME/go ```
## Tooling Go comes with its own tool, called `go`. It manages many things, and any missing functionality can be covered with third party tools.
## Go tool The `go` tool can handle fetching dependencies, running tests, installing binaries, running programs, linting, code formatting, and many others! ```bash build compile packages and dependencies clean remove object files env print Go environment information fix run go tool fix on packages fmt run gofmt on package sources get download and install packages and dependencies install compile and install packages and dependencies list list packages run compile and run Go program test test packages tool run specified go tool version print Go version vet run go tool vet on packages ```
## Documentation The Go project cares a lot about documentation, and `golint` enforces clean code that can be parsed for generation of documentation. The `godoc` tool can parse code to render documentation to stdout. ```bash $ godoc fmt Formatter use 'godoc cmd/fmt' for documentation on the fmt command type Formatter interface { Format(f State, c rune) } Formatter is the interface implemented by values with a custom formatter. The implementation of Format may call Sprint(f) or Fprint(f) etc. to generate its output. ``` The `godoc` tool also contains a webserver! ```bash $ godoc -http=":8082" $ open http://localhost:8082 ```
## Third Party Tools The third party tooling is very good considering how young Go is. Many of the tools are built in Go, and write to stdout so can be easily parsed and plugged into any editors easily. A short list of essential third party tools are: ```bash glide Dependency Management gocode Allows package inspection for autocompletion golint Linting for go source code godef Go to definition ```
## Using Go The commands `go get`, `go build`, `go run`, and `go test` will probably be your most commonly used commands. ## Cross compilation To cross compile to a different system architecture, prefix with the relevant environment variables. Cross compiling for Windows from OSX: ```bash GOOS=windows GOARCH=amd64 go build main.go ```
## Editors - [Atom](https://atom.io/) + [go-plus](https://github.com/joefitzgerald/go-plus) - [Sublime Text](https://www.sublimetext.com/) + [gosublime](https://github.com/DisposaBoy/GoSublime) - [IntelliJ IDEA Community](https://www.jetbrains.com/idea/download/) + [go-lang-idea-plugin](https://github.com/go-lang-plugin-org/go-lang-idea-plugin) - [Vim](http://www.vim.org/) + [vim-go](https://github.com/fatih/vim-go) - [VSCode](https://code.visualstudio.com/) + [vscode-go](https://github.com/Microsoft/vscode-go)
## Program Structure Go has a very opinionated structure. There are tools to get around this but it is a better idea to follow best practices.
## GOPATH The GOPATH is where everything is stored. The GOPATH has the following tree: ```bash $GOPATH ├── bin └── gocode └── goimports └── goreturns ├── pkg └── darwin_amd64 └── github.com └── nii236 └── repo-name └── src └── github.com └── nii236 └── repo-name ```
## Packages These are basically libraries or modules in other languages and is namespaced. Exported identifiers in each package allows users to consume the packages as intended. Packages are fetched with `go get` and are imported with a fully qualified name and will fetch the HEAD everytime. ```go import "github.com/exampleUser/exampleRepo" ```
## Vendoring Since Go 1.5, there has been support for vendoring and dependency management (which allows us to control which versions of packages we fetch). There have been many third party tools created for this, as the creators of Go do not see it as necessary (as they live in Google's monorepo environment): - [gb](https://getgb.io/) - [godep](https://github.com/tools/godep) - [glide](https://github.com/Masterminds/glide)
## Exported and Unexported Identifiers If the first letter of a function is a capital, then it is considered an exported identifier and can be accessed from outside the package. ```go // ExportedFunction is a function that is // accessible outside of the package func ExportedFunction() {} ``` If the first letter is lowercase instead, it will be considered private. ```go func unexportedFunction() {} ```
## Variables There are a few ways of declaring variables. ```go var a, b, c int var i, j, k = true, 2.3, "four" f, err := os.Open(name) ```
## Types Go's type system is very simplistic and not easily extensible.
## Data Types - Integers - Floats - Complex Numbers - Booleans - Strings - Constants
## Composite Types - Arrays - Slices - Maps - Struct - JSON - Text and HTML Templates
## Program Flow [Link](https://play.golang.org/p/iozXXYlnZ6) Methods to control the program flow are similar to C based languages.
## Conditionals The `if` statement behaves as expected. ```go if condition { // Do something } ``` You can also assign temporary variables. ```go if a := something; condition { // Assign a variable or run a function then do something } ```
## Select The select statement lets a goroutine wait on multiple communication operations. ```go for i := 0; i < 2; i++ { select { case msg1 := <- c1: fmt.Println("received", msg1) case msg2 := <- c2: fmt.Println("received", msg2) } } ```
## Switch These statements express conditionals across many branches. ```go i := 2 fmt.Print("write ", i, " as ") switch i { case 1: fmt.Println("one") case 2: fmt.Println("two") case 3: fmt.Println("three") } ```
## Loops There is only a single reserved word for loops. ```go for initialization; condition; post { // Vanilla loop } for condition { // While loop } for { // Infinite loop } ```
## Range Iterable objects can also be `range`d over. ```go a := [1, 2, 3] for _, v := range a { fmt.Println(v) } ```
## Structs [Link](https://play.golang.org/p/YlrlQIwEO2) These are a very important part of Go and are worth focusing on. Structs are typed collections of fields. Structs are also what enables Go's composition based object oriented programming.
## Struct Example Here is a struct declaration of a Person containing a Name of type string, and an Age of type int. ```go type Person struct { Name string Age int } ```
## Instantiating Structs You refer to struct objects with their memory address when assigning to a variable ```go func main() { p := &Person{"John", 29} fmt.Println(p.Name) } ```
## Embedding Structs Go does not provide the typical, type-driven notion of subclassing, but it does have the ability to “borrow” pieces of an implementation by embedding types within a struct or interface. ```go type Person struct { Name string Age int } type Developer struct { Person Company string } type Student struct { Person University string } ```
## Attaching Methods Use struct pointers only if you need to mutate the object. ```go func (p Person) sayHello() { fmt.Println("Hello, I am", p.Name) } func (d Developer) sayHello() { fmt.Println("BeepBoop I am", d.Name) } func (d *Developer) changeName(in string) { d.Name = in } ```
Run the program. ```go func main() { p := &Person{"Andy", 32} d := &Developer{Person{"John", 29}, "TFG"} p.sayHello() // Prints "Hello, I am Andy" d.sayHello() // Prints "BeepBoop I am John" d.changeName("Johnny") d.sayHello() // Prints "BeepBoop I am Johnny" } ```
## Procedures Go allows both functions and methods with collections of functions passed around as interfaces.
## Functions Go supports first class functions that do not need to be attached or instantiated from a class/object Functions in Go can have *multiple return values* ```go func exampleFunction(varName string) ([]int, error) { ... } ```
## Anonymous Functions [Link](https://play.golang.org/p/0tOpD0O1p8) Go supports anonymous functions. They can also be used as a return value given the same function signature. ```go // AnonymousFunc is an anonymous function type // that can be used as a return value. type AnonymousFunc func() []int // Parentfunc simply returns AnonymousFunc. func Parentfunc() AnonymousFunc { return func() []int { return []int{1, 2} } } ``` This can be useful for creating wrappers around functions such as building middleware for HTTP handlers.
## Methods Go also allows you to attach methods to structs ```go func (s *SomeStruct) mutableMethod(a int) int { ... } func (s SomeStruct) immutableMethod(a int) int { ... } ```
## Interfaces [Link](https://play.golang.org/p/F6ZCguKs55) Interfaces in Go provide a way to specify the behavior of an object: if something can do *this*, then it can be used here. Interfaces are satisfied **implicitly**. ```go type ExampleInterface interface { methodOne(in string) string methodTwo(in []int) (int, error) } type First struct { RandomInfo string} type Second struct { OtherInfo int} func (s *First) methodOne(a int) string {} func (s *First) methodTwo(a int) (int, error) func (s *Second) methodOne(a int) string {} func (s *Second) methodTwo(a int) (int, error) {} func satisfied (ex ExampleInterface) { // Either first or second struct can be used! } ```
## Hello World We're going to start with a simple hello world program.
## Hello World Example [Link](https://play.golang.org/p/I3l_5RKJts) The below code will get you going: ```go package main import "fmt" func main() { fmt.Println("Hello, 世界") } ``` To run it: ``` $ go run main.go Hello, 世界 ```
## Command Line Tools Let's have a look at parsing command line flags. Go is quite good at building command line tools.
## Command Line Tool Example ```go func main() { var cmd string flag.StringVar(&cmd, "cmd", cmd, `cmd can be either "hello" or "bye"`) flag.Parse() switch cmd { case "hello": fmt.Println("Hello!") case "bye": fmt.Println("Bye!") default: flag.Usage() } } ```
Lets build it first then run it. ```bash $ go build main.go $ ./go-crashcourse Usage of ./go-crashcourse: -cmd string cmd can be either "hello" or "bye" ```
## Concurrency Go has two main forms of managing concurrency. Goroutines and Channels.
## Go Routines Go routines are light weight threads that are managed by the Go runtime. To run a function in a new go routine, just put "go" before the function call.
## Go routine example [Link](https://play.golang.org/p/W51Ls4Tlsu) ``` // Routines is an example of Go routines. func Routines() { go say("let's go!", 3*time.Second) go say("ho!", 2*time.Second) go say("hey!", 1*time.Second) time.Sleep(4 * time.Second) fmt.Println("Finished") } func say(text string, delay time.Duration) { time.Sleep(delay) fmt.Println(text) } ```
## Channels Channels are typed conduits for synchronization and communication between go routines.
## Go channel example [Link](https://play.golang.org/p/a8ka_5zoEG) ```go // Channels is an example of Go channels. func Channels() { messages := make(chan string) go func() { messages <- "ping" }() msg := <-messages fmt.Println(msg) } ```
## Web Client and Server Go has a very solid standard library and its common in the community to focus on solving most problems with the standard library.
## Client The net/http package provides an HTTP client. ``` func main() { r, err := http.Get("http://www.golang.org/") if err != nil { log.Fatal(err) } if r.StatusCode != http.StatusOK { log.Fatal(r.Status) } io.Copy(os.Stdout, r.Body) } ```
## Server The net/http package also provides an HTTP server. ``` func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "Hello, web") }) fmt.Println("Starting server") err := http.ListenAndServe("localhost:8080", nil) if err != nil { log.Fatal(err) } } ``` This is a high-performance, DoS-hardened and production-ready web server. It serves [dl.google.com](http://dl.google.com).
## Server with Templated HTML We will need to fetch our first dependency for this code. ```bash go get github.com/gorilla/mux ``` The code below creates a webserver that handles only a single route, `/`, unlike before. ```go import "github.com/gorilla/mux" // PartTwo runs a web server with templating func PartTwo() { rt := mux.NewRouter().StrictSlash(true) // Index is described in the slide below rt.HandleFunc("/", Index) log.Println("PART TWO: Starting server of localhost:8081") log.Fatal(http.ListenAndServe(":8081", rt)) } ``` The route handler Index will be handled next.
## Route Handlers `Index` will be executed when the route `/` is hit. ```go //Index is the handler for root path func Index(w http.ResponseWriter, r *http.Request) { pd := PageData{ Title: "Index Page", Body: "This is the body of the page", } tmpl, err := htmlTemplate(pd) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) return } w.Write([]byte(tmpl)) } ```
## Templating HTML templating is a powerful feature of Go and lets you render data-driven HTML. As of Go 1.6, blocks are introduced which let you build templates on other templates. ```go func htmlTemplate(pd PageData) (string, error) { html := `<HTML> <head> <title> {{.Title}} </title> </head> <body> {{.Body}} </body> ` tmpl, err := template.New("index").Parse(html) if err != nil { return "", err } var out bytes.Buffer if err := tmpl.Execute(&out, pd); err != nil { return "", err } return out.String(), nil } ```
Now we can update our CLI tool and execute our server. ```bash $ go build ./go-crashcourse -cmd serve2 Running server! 2016/03/04 10:57:19 PART TWO: Starting server of localhost:8081 ``` Next we visit [localhost:8081](http://localhost:8081) ```bash open http://localhost:8081 ```
## Testing Go has a robust standard tooling for table based XUnit type tests. Additional third party libraries are available for more BDD style assertions.
## Testing Example First we will build the test suite. ```go package add_test import ( "testing" "github.com/nii236/gotraining/testing" ) var tests = []struct { in []int out int }{ {[]int{1, 2}, 3}, {[]int{-1, 2}, 1}, {[]int{1, 0}, 1}, } ```
Next we will write the test itself. ```go func TestFunc(t *testing.T) { for _, tt := range tests { got := add.Do(tt.in[0], tt.in[1]) expected := tt.out if got != tt.out { t.Errorf("Error! Got %d, expected %d", got, expected) } } } ```
Now we will write the code that satisfies the test. ```go package add //Do runs a test func given two integers func Do(a int, b int) int { return a + b } ```
And finally we can run the test and see how we go! ```bash $ go test ./... ? github.com/nii236/gotraining/go-crashcourse [no test files] ? github.com/nii236/gotraining/go-crashcourse/concurrency [no test files] ? github.com/nii236/gotraining/go-crashcourse/hello [no test files] ? github.com/nii236/gotraining/go-crashcourse/serve [no test files] ? github.com/nii236/gotraining/go-crashcourse/structs [no test files] ok github.com/nii236/gotraining/go-crashcourse/testing 0.005s ```
## The End.