Slide 1

Slide 1 text

Go Go Gopher An Introduction to Go

Slide 2

Slide 2 text

Go?

Slide 3

Slide 3 text

History Created by Google Robert Griesemer, Rob Pike & Ken Thompson Open-sourced November 2009 Go 1.0 released March 2012

Slide 4

Slide 4 text

Goals move away from verbose type systems of java / c++ ease development of multi-threaded applications easy dependency management & fast compilation “Do less, enable more”

Slide 5

Slide 5 text

The Language Designed for concurrent systems programming, Strongly and statically typed, Compiled, Garbage collected, Object oriented (ish), Small, opinionated, and done.

Slide 6

Slide 6 text

Hello World package main ! import ( "fmt" ) ! func main() { fmt.Println("Hello, World!") }

Slide 7

Slide 7 text

Hello World, the HTTP Version package main ! import ( "fmt" "net/http" ) ! func handle(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "Hello, World.") } ! func main() { http.HandleFunc("/", handle) http.ListenAndServe(":8080", nil) }

Slide 8

Slide 8 text

Data & Types

Slide 9

Slide 9 text

Variable Declaration var x T // Variable x of type T with a zero value var x T = v // Variable x of type T with value v var x = v // Variable x with value v, implicit typing x := v // Short variable declaration (type inferred) x, y := v1, v2 // Double declaration (similar with var) make(T) // make takes a type T, which must be a slice, // map or channel type, optionally followed by // a type-specific list of expressions new(T) // new allocates zeroed storage for a new // value of type T returns its address

Slide 10

Slide 10 text

Zero Values All types have a zero value

Slide 11

Slide 11 text

Zero Values 0 // numeric false // boolean "" // string nil // pointer, channel, func, // interface, map, or slice

Slide 12

Slide 12 text

Blank Identifier /dev/null for values

Slide 13

Slide 13 text

Blank Identifier // Importing a library just for side effects import _ "mylib" ! // Discarding a return value when we don't need it if _, err := os.Stat(path); os.IsNotExist(err) { fmt.Printf("%s does not exist\n", path) }

Slide 14

Slide 14 text

Type Conversion // T(v) converts the value v to type T i := 42 f := float64(i) u := uint(f)

Slide 15

Slide 15 text

Types

Slide 16

Slide 16 text

Types Arrays slices maps booleans numerics strings pointers structs channels

Slide 17

Slide 17 text

Booleans b1 := true // type is bool b2 := false

Slide 18

Slide 18 text

Numerics uint8,16,32,64, int8,16,32,64, float32,64, complex64,128 int + uint (32 or 64 bits, depending on platform) byte (alias for uint8) rune (alias for int32)

Slide 19

Slide 19 text

Numerics n1 := 123 // int n2 := 123.456 // float32/64, depending on arch n3 := 1e10 // float32/64, depending on arch n4 := uint8(123) // uint n5 := float32(123) // float32

Slide 20

Slide 20 text

Strings s1 := `Raw string literal` s2 := "Interpreted string literal" ! "⽕火" // UTF-8 input text `⽕火` // UTF-8 input text as a raw literal "\u65e5" // explicit Unicode code points "\U000065e5" // explicit Unicode code points "\xe6\x97\xa5" // explicit UTF-8 bytes

Slide 21

Slide 21 text

Runes 'x' '\n' '\U00101234' ! // range on a string yields runes for _, r := range "foo" { fmt.Printf("%s, %T\n", string(r), r) } ! // f, int32 // o, int32 // o, int32

Slide 22

Slide 22 text

Arrays fixed-length data types contiguous block of elements of the same type underlying data structure for both slices and maps The length of an array is part of its type

Slide 23

Slide 23 text

Arrays var a1 [10]int // Declare int array with a length of 10 a1[3] = 42 // Write a value to a specific index i := a[3] // Read a value from a specific index ! a2 := [3]int{10, 20, 30} // Declare using an array literal a3 := [...]int{10, 20, 30} // Declare with a calculated size a4 := [3]int{1: 10, 2: 20} // Only intialise specific values a5 := [3]int{} // All positions set to zero-value ! l := len(a5) // Built-in len() function reads array size

Slide 24

Slide 24 text

Slices Abstracts an underlying array lightweight reference to array + length + capacity

Slide 25

Slide 25 text

Slices s1 = make([]int, 5) // Zeroed int slice: len(s1) == 5 s2 = make([]int, 0, 5) // len(s2) == 0, cap(s2) == 5 ! var s3 []int // Declare a nil slice s4 := []int{1, 2, 3, 4} // Declare and initialise a slice s5 := []string{0:"a", 2:"c"} // ["a", "", "c"] ! s4 := s2[lo:hi] // Creates a new slice from index lo to hi-1 s5 := s2[1:4] // Slice from index 1 to 3 s6 := s2[:3] // Missing low index implies 0 s7 := s2[3:] // Missing high index implies len(a)

Slide 26

Slide 26 text

Appending to a Slice func p(x []int) { fmt.Printf("len=%d cap=%d %v\n", len(x), cap(x), x) } ! var s []int // Define a nil int slice p(s) // len=0 cap=0 [] ! s = append(s, 0) // append() works on nil slices p(s) // len=1 cap=1 [0] ! s = append(s, 1) // The slice grows as necessary p(s) // len=2 cap=2 [0 1] ! s = append(s, 2, 3, 4) // append() is variadic p(s) // len=5 cap=6 [0 1 2 3 4]

Slide 27

Slide 27 text

Maps m1 := make(map[string]int) m1["foo"] = 42 fmt.Println(m1) // map[foo:42] ! m2 := map[string]int{ "a": 1, "b": 2, "c": 3, // trailing comma is required before a newline } fmt.Println(m2) // map[a:1 b:2 c:3]

Slide 28

Slide 28 text

Mutating Maps m := map[string]int{"a": 1, "b": 2} fmt.Println(m) // map[a:1 b:2] ! m["c"] = 3 fmt.Println(m) // map[a:1 b:2 c:3] ! delete(m, "b") fmt.Println(m) // map[a:1 c:3] ! if v, ok := m["b"]; !ok { fmt.Println(v) // 0 (zero value for an int) }

Slide 29

Slide 29 text

Pointers var p *int // Variable p of type *int (int pointer) i := 42 // Variable i of type int with value 42 p = &i // Assign the address of i to p ! fmt.Println(p) // Output the value of p (the address of i) fmt.Println(*p) // Output the value of i by using * to // dereference the pointer p

Slide 30

Slide 30 text

Structs type Rectangle struct { Width int Height int } ! r1 := Rectangle{1, 2} // Create a new Rectangle with w + h r1.Width = 3 // Set the width to a new value fmt.Printf("Width = %d; Height = %d\n", r1.Width, r1.Height)

Slide 31

Slide 31 text

Structs type Rectangle struct { Width int Height int } ! var r2 Rectangle // Value is nil r3 := Rectangle{Height: 1} // w=0 (int zero value), h=1 r4 := Rectangle{} // w=0, h=0 r5 := &Rectangle{1, 2} // Has type *Rectangle ! r5.Height = 4 // Dereferencing of struct fields through // a pointer is transparent ! fmt.Println(r2, r3, r4, r5) // {0 0} {0 1} {0 0} &{1 4}

Slide 32

Slide 32 text

Struct Embedding type Vehicle struct { speed int passengers int } ! type Weapon struct { damage int } ! type Tank struct { Vehicle Weapon }

Slide 33

Slide 33 text

Struct Embedding type Job struct { Command string *log.Logger } ! func NewJob(command string, logger *log.Logger) *Job { return &Job{command, logger} } ! job := NewJob(...) job.Log("starting now...")

Slide 34

Slide 34 text

Marshalling Structs import ( "encoding/json" ) ! type Rectangle struct { Width int `json:"width"` Height int `json:"height"` } ! r := Rectangle{3, 4} j, _ := json.Marshal(r) fmt.Println(string(j)) // {"width":1,"height":2}

Slide 35

Slide 35 text

Functions func f1() {} // Simple function definition func f2(s string, i int) {} // Function that accepts two args func f3(s1, s2 string) {} // Two args of the same type func f4(s ...string) {} // Variadic function ! func f5() int { // Return type declaration return 42 } ! func f6() (int, string) { // Multiple return values return 42, "foo" }

Slide 36

Slide 36 text

Functions // Named return values act like variables func f7() (i int, s string) { i = 42 s = "foo" return // Naked return returns current values of vars } ! f7 := func() {} // Function as a value ! i := 42 func() { fmt.Println(i) // Function as a closure }()

Slide 37

Slide 37 text

Functions All function calls are pass-by-value

Slide 38

Slide 38 text

Functions: defer func ProcessFile(path string) { f, _ := os.Open(path) defer f.Close() // Do something with the file... }

Slide 39

Slide 39 text

Functions: defer func main() { defer func() { fmt.Println("One more thing...") }() ! panic("PANIC!") } ! // $ go run scratch.go // One more thing... // panic: PANIC!

Slide 40

Slide 40 text

Methods type Rectangle struct { Width int Height int } ! func (r Rectangle) Area() int { return r.Width * r.Height } ! func main() { r := Rectangle{Width: 3, Height: 4} fmt.Println(r.Area()) // Area 12 }

Slide 41

Slide 41 text

Pointer Receivers Use a pointer receiver if you need to... 1. avoid copying a large data structure 2. mutate the value of the receiver

Slide 42

Slide 42 text

Pointer Receivers func (r Rectangle) ScaleVal(i int) { r.Width = r.Width * i r.Height = r.Height * i } ! func (r *Rectangle) ScalePtr(i int) { // ... } ! r := Rectangle{Width: 3, Height: 4} r.ScaleVal(2) fmt.Printf("%+v\n", r) // {Width:3, Height:4} r.ScalePtr(2) fmt.Printf("%+v\n", r) // {Width:6, Height:8}

Slide 43

Slide 43 text

Interfaces Provide polymorphism no implements keyword interfaces are satisfied implicitly

Slide 44

Slide 44 text

Interfaces type Speaker interface { Speak() string } ! type Dog struct { } func (d Dog) Speak() string { return "Woof" } ! type Robot struct { } func (r Robot) Speak() string { return "Danger!" } ! things := []Speaker{Dog{}, Robot{}} for _, t := range things { fmt.Println(t.Speak()) }

Slide 45

Slide 45 text

Interface Embedding type Reader interface { Read(p []byte) (n int, err error) } ! type Writer interface { Write(p []byte) (n int, err error) } ! // ReadWriter is the interface that combines the // Reader and Writer interfaces. type ReadWriter interface { Reader Writer }

Slide 46

Slide 46 text

All Types are Explicit int != *int != []int != *[]int != []*int

Slide 47

Slide 47 text

Control Structures

Slide 48

Slide 48 text

If if x > 0 { // ... } else if x < 0 { // ... } else { // ... } ! if err := doWork(); err != nil { // ... }

Slide 49

Slide 49 text

For for x := 0; x < 10; x++ { // ... } ! x := false for !x { // ... } ! for { // ... }

Slide 50

Slide 50 text

For // If looping over an array, slice, string or map, // or reading from a channel, use a range clause // to manage the loop: for index, value := range mySlice { // ... }

Slide 51

Slide 51 text

For for p, c := range “⽇日本 語" { fmt.Printf("%#U starts at byte %d\n", c, p) } ! // U+65E5 '⽇日' starts at byte 0 // U+672C '本' starts at byte 3 // U+0020 ' ' starts at byte 6 // U+8A9E '語' starts at byte 7

Slide 52

Slide 52 text

Switch x := "b" switch(x) { case "a": // ... case "b": // ... default: // ... } switch { case x == "a": // ... fallthrough case x == "b": // ... }

Slide 53

Slide 53 text

Switch var t interface{} t = functionReturningSomeType() ! switch t := t.(type) { case string: // String type value case int: // Integer type value case *bool: // Boolean pointer type value default: // Unhandled type }

Slide 54

Slide 54 text

Error Handling type error interface { Error() string }

Slide 55

Slide 55 text

Error Handling func Sqrt(f float64) (float64, error) { if f < 0 { return 0, errors.New("Square root of negative number") } // ... } ! f, err := Sqrt(-1) if err != nil { fmt.Println(err) }

Slide 56

Slide 56 text

Concurrency

Slide 57

Slide 57 text

Concurrency Go has concurrency primitives built in goroutines for concurrent functions channels for communicating between goroutines “Share By Communicating”

Slide 58

Slide 58 text

Goroutines Lightweight threads of execution multiplexed across os threads very cheap to use

Slide 59

Slide 59 text

goroutines func doWork(i int) { time.Sleep(time.Millisecond * 500) fmt.Println(i) } ! func main() { for i := 1; i <= 5; i++ { doWork(i) } }

Slide 60

Slide 60 text

goroutines $ time go run g1.go 1 2 3 4 5 go run g1.go ... 2.757 total

Slide 61

Slide 61 text

goroutines func doWork(i int) { time.Sleep(time.Millisecond * 500) fmt.Println(i) } ! func main() { for i := 1; i <= 5; i++ { go doWork(i) // concurrency! } }

Slide 62

Slide 62 text

goroutines $ time go run g2.go go run g2.go ... 0.247 total

Slide 63

Slide 63 text

GOroutines func doWork(i int) { time.Sleep(time.Millisecond * 500) fmt.Println(i) } ! func main() { var wg sync.WaitGroup for i := 1; i <= 5; i++ { wg.Add(1) go func(x int) { defer wg.Done() doWork(x) }(i) } wg.Wait() }

Slide 64

Slide 64 text

goroutines $ time go run g3.go 4 1 5 2 3 go run g3.go ... 0.752 total

Slide 65

Slide 65 text

Channels c1 := make(chan int) // Create an unbuffered channel of type int c1 <- 42 // Send a value to the channel v := <-c1 // Receive a value from ch ! // The above will deadlock, because a write to an unbuffered // channel will block until the value has been received ! c2 := make(chan int, 1) // Create a buffered channel c2 <- 42 v := <-c2

Slide 66

Slide 66 text

Channels c3, c4 := make(chan int), make(chan int) ! close(c3) // Close the channel for writing v, ok := <-c3 // Receive, testing for closure if !ok { fmt.Println("Channel closed!") } ! // Read from channel until it is closed for i := range c4 { fmt.Println(i) } ! c5 := make(chan chan int) // A channel of int channels

Slide 67

Slide 67 text

Channels var done chan bool ! func doWork() { fmt.Println("Working...") time.Sleep(time.Second) fmt.Println("Done.") done <- true } ! func main() { go doWork() <-done }

Slide 68

Slide 68 text

Channels func doWork(i int, c chan int) { time.Sleep(time.Millisecond * 500) c <- i } ! func main() { c := make(chan int) for i := 1; i <= 5; i++ { go doWork(i, c) } ! for i := 1; i <= 5; i++ { i := <-c fmt.Println(i) } }

Slide 69

Slide 69 text

Channels A send to a nil channel blocks forever A receive on a nil channel blocks forever A send to a closed channel panics A receive on a closed channel returns the zero value

Slide 70

Slide 70 text

select func doWork(c chan int, done chan struct{}) { select { case x := <-c: fmt.Printf("%d received", x) case <-time.After(time.Second * 1): fmt.Println("Timeout") case <-done return } }

Slide 71

Slide 71 text

Concurrency example: Worker Pools func doWork(queue <-chan int, results chan<- int) { for i := range queue { time.Sleep(time.Millisecond * time.Duration(rand.Intn(1000))) results <- i * 2 } } ! func publishJobs(jobs int, queue chan<- int) { for i := 1; i <= jobs; i++ { queue <- i } close(queue) }

Slide 72

Slide 72 text

func startWorkers(c int, queue <-chan int, results chan<- int) { var wg sync.WaitGroup ! for i := 1; i <= c; i++ { wg.Add(1) go func() { defer wg.Done() doWork(queue, results) }() } ! go func() { wg.Wait() close(results) }() } Concurrency example: Worker Pools

Slide 73

Slide 73 text

func main() { queue := make(chan int) results := make(chan int) ! go startWorkers(5, queue, results) go publishJobs(queue) ! for r := range results { fmt.Println(r) } } Concurrency example: Worker Pools

Slide 74

Slide 74 text

Mutexs var counter = struct{ sync.RWMutex m map[string]int }{m: make(map[string]int)} ! counter.RLock() // Read lock n := counter.m["some_key"] counter.RUnlock() fmt.Println("some_key:", n) ! counter.Lock() // Write lock counter.m["some_key"]++ counter.Unlock()

Slide 75

Slide 75 text

sync/atomic var ops uint64 = 0 ! for i := 0; i < 50; i++ { go func() { for { atomic.AddUint64(&ops, 1) runtime.Gosched() } }() } ! time.Sleep(time.Second) ! opsFinal := atomic.LoadUint64(&ops) fmt.Println("ops:", opsFinal)

Slide 76

Slide 76 text

Code Organisation

Slide 77

Slide 77 text

Packaging all Go programs are organised into packages all .go files must declare their package packages must be contained in a single directory names should be short, concise and lower-case

Slide 78

Slide 78 text

Package Main Package main denotes that a binary should be built all executables must have a package main function main() must also exist for binary to be built

Slide 79

Slide 79 text

Imports import ( "fmt" // Package from stdlib "net/http" // Package from stdlib myfmt "mylib/fmt" // Specifying a custom identifier ! // Import remote stringutil package “github.com/golang/example/stringutil" ! // Remote package with blank identifier _ "github.com/go-sql-driver/mysql" )

Slide 80

Slide 80 text

Exporting Identifiers No concept of public / package / private identifiers are either exported from a package, or not identifiers starting with a capital are exported

Slide 81

Slide 81 text

Exporting Identifiers package mylib ! type Foo string // Exported, accessible outside the package type bar string // Only accessible within the mylib package ! func NewBar(s string) bar { return bar(s) }

Slide 82

Slide 82 text

Exporting Identifiers package main ! import "mylib" ! func main() { // This is fine, because Foo is exported from mylib s1 := mylib.Foo("a") ! // Compile error: "cannot refer to unexported name" s2 := mylib.bar("b") ! // We can still get a bar value through this function s3 := mylib.NewBar("c") }

Slide 83

Slide 83 text

Workspaces a workspace is a directory hierarchy must contain src, pkg & bin directories in the root $GoPATH gives the location of your workspace Keep all go code in one workspace

Slide 84

Slide 84 text

Workspaces bin/ hello # command executable pkg/ linux_amd64/ github.com/golang/example/ stringutil.a # package object src/ github.com/golang/example/ hello/ hello.go # command source stringutil/ reverse.go # package source reverse_test.go # test source

Slide 85

Slide 85 text

Tooling

Slide 86

Slide 86 text

Tooling go build: compile packages & dependencies go run: compile & run an application go test: run your test cases go get: download and install packages

Slide 87

Slide 87 text

Tooling gofmt: format your code in the only acceptable way goimports: go fmt + import management golint: checks code for style violations go vet: find common coding errors oracle: source analysis tool

Slide 88

Slide 88 text

and finally...

Slide 89

Slide 89 text

Who uses it?

Slide 90

Slide 90 text

What for? Game backends, crawlers & scrapers, web services, queueing, HTTP caching, logging, data stores, service coordination, real-time communication, WebSockets, HTTP routing, metric, analytics, infrastructure management, provisioning...

Slide 91

Slide 91 text

Find out more https://golang.org/ref/spec https://tour.golang.org/ https://golang.org/doc/code.html https://golang.org/doc/effective_go.html

Slide 92

Slide 92 text

The end @timblair