Slide 1

Slide 1 text

Go 102 A Go Workshop

Slide 2

Slide 2 text

Topics Go Basics Object Oriented Programming in Go Concurrency

Slide 3

Slide 3 text

Information / timblair / go-102-workshop

Slide 4

Slide 4 text

The Basics

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

Types Arrays slices maps booleans numerics strings pointers structs channels

Slide 8

Slide 8 text

Types Arrays slices maps booleans numerics strings pointers structs channels

Slide 9

Slide 9 text

Basic Types b1 := true // type is bool b2 := false n1 := 123 // int n2 := 123.456 // float32/64 n3 := 1e10 // float32/64 n4 := uint8(123) // uint n5 := float32(123) // float32 s1 := `Raw string literal` s2 := "Interpreted string literal"

Slide 10

Slide 10 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

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

Structs type rectangle struct { width int height int } r1 := rectangle{1, 2} // New rectangle with w + h r1.width = 3 // Set width to a new value fmt.Printf("Width = %d; Height = %d\n", r1.width, r1.height) var r2 rectangle // w=0, h=0 (int zero values) r4 := rectangle{} // w=0, h=0 r3 := rectangle{height: 1} // w=0, h=1

Slide 13

Slide 13 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 14

Slide 14 text

Exercise Declare a struct type to maintain information about a person. Declare a function that creates new values of your type. Call this function from main and display the value.

Slide 15

Slide 15 text

What have we covered? Built-in Types & value declaration All types have a zero value structs as collections of named fields functions

Slide 16

Slide 16 text

Object Orientation

Slide 17

Slide 17 text

Object Orientation Is Go an object-oriented language? Yes and no.

Slide 18

Slide 18 text

Object Orientation Abstraction Encapsulation Inheritance Polymorphism

Slide 19

Slide 19 text

Object Orientation OOP is about objects. An object is a data structure that has both state and behaviour

Slide 20

Slide 20 text

Methods

Slide 21

Slide 21 text

Methods type rectangle struct { width int height int } func area(r rectangle) int { return r.width * r.height } func main() { r := rectangle{3, 4} fmt.Println(area(r)) // area 12 }

Slide 22

Slide 22 text

Methods A method is a function bound to a receiver

Slide 23

Slide 23 text

Methods type rectangle struct { width int height int } func (r rectangle) area() int { return r.width * r.height } func main() { r := rectangle{3, 4} fmt.Println(r.area()) // area 12 }

Slide 24

Slide 24 text

Methods A receiver can be any named type

Slide 25

Slide 25 text

Methods // function, called with area(r) func area(r rectangle) int { return r.width * r.height } // method, called with r.area() func (r rectangle) area() int { return r.width * r.height }

Slide 26

Slide 26 text

Methods Declare a new struct type to hold information about a tennis player, including the number of matches played and the number won. Add a method to this type that calculates the win ratio for the player. Create a new player, and output the win ratio for them.

Slide 27

Slide 27 text

Methods methods are functions that are bound to a receiver A receiver can be any named type Methods are effectively syntactic sugar

Slide 28

Slide 28 text

Interfaces

Slide 29

Slide 29 text

Interfaces Provide polymorphism Declare behaviour

Slide 30

Slide 30 text

Interfaces no implements keyword interfaces are satisfied implicitly

Slide 31

Slide 31 text

Interfaces type speaker interface { speak() string }

Slide 32

Slide 32 text

Interfaces type hipster struct { } func (h hipster) speak() string { return "Amazeballs" } func (h hipster) trimBeard() { /* ... */ } type dog struct { } func (d dog) speak() string { return "Woof" } func (d dog) wagTail() { /* ... */ } type robot struct { } func (r robot) speak() string { return "Does not compute" } func (r robot) becomeSentient() { /* ... */ }

Slide 33

Slide 33 text

Interfaces // We can treat a hipster as a speaker var s1 speaker s1 = hipster{} // We can also create a slice of different speakers speakers := []speaker{hipster{}, dog{}, robot{}} for _, s := range speakers { fmt.Printf("%T: %s\n", s, s.speak()) } // main.hipster: Amazeballs // main.dog: Woof // main.robot: Does not compute

Slide 34

Slide 34 text

Interfaces type email struct { name string address string } e := email{"Tim Blair", "[email protected]"} fmt.Println(e) // {Tim Blair [email protected]}

Slide 35

Slide 35 text

Interfaces // The Stringer interface found in fmt package type Stringer interface { String() string }

Slide 36

Slide 36 text

Interfaces type email struct { name string address string } func (e email) String() string { return fmt.Sprintf("\"%s\" <%s>", e.name, e.address) } e := email{"Tim Blair", "[email protected]"} fmt.Println(e) // "Tim Blair"

Slide 37

Slide 37 text

Interfaces Define an interface with a method Area(). Create types for Square, Rectangle and Circle, and ensure they satisfy your interface. Create a function that accepts a value of your interface type and outputs the area, and call this function for different shapes.

Slide 38

Slide 38 text

Interfaces Interfaces are types that declare behaviour they provide polymorphism behaviour no `implements` keyword; satisfied implicitly

Slide 39

Slide 39 text

Embedding

Slide 40

Slide 40 text

Embedding type sphere struct { x, y, z, radius int } type cube struct { x, y, z, length int }

Slide 41

Slide 41 text

Embedding type point struct { x, y, z int } type sphere struct { point point radius int } type cube struct { point point length int } var s sphere s.point.x = 5 s.point.y = 6 s.point.z = 7 s.radius = 3

Slide 42

Slide 42 text

Embedding type point struct { x, y, z int } type sphere struct { point radius int } type cube struct { point length int } var s sphere s.x = 5 s.y = 6 s.z = 7 s.radius = 3

Slide 43

Slide 43 text

Embedding s1 := sphere{point{1, 2, 3}, 5} s2 := sphere{ point: point{ 1, 2, 3, }, radius: 5, // required trailing comma }

Slide 44

Slide 44 text

Embedding type robot struct { } func (r robot) talk() { fmt.Println("Bzzzzzbt") } type robby struct { robot } robby := robby{} robby.talk() // Bzzzzzbt

Slide 45

Slide 45 text

Embedding type robot struct { } func (r robot) talk() { fmt.Println("Bzzzzzbt") } type robby struct { robot } func (r robby) talk() { fmt.Println("Again?") } robby := robby{} robby.talk() // Again?

Slide 46

Slide 46 text

Embedding type talker interface { talk() } type robot struct{} func (r robot) talk() { fmt.Println("Bzzzzzbt") } type robby struct { robot } func talk(t talker) { t.talk() } talk(robby{})

Slide 47

Slide 47 text

Embedding Create a user type, and an admin type that embeds a user. Create a Notifier interface, and make your user type satisfy that interface. Write a function that accepts a value of the interface type, and ensure it works correctly when passed a value of your admin type.

Slide 48

Slide 48 text

Embedding composition is supported through type embedding anonymous struct fields are said to be embedded Both inner types and methods are promoted Promoted methods can satisfy an interface

Slide 49

Slide 49 text

Composition

Slide 50

Slide 50 text

Composition "Everyone knows composition is more powerful than inheritance, Go just makes this non optional." –– Dave Cheney: http://bit.ly/dctlg

Slide 51

Slide 51 text

Composition type point struct { x, y int } type mover interface { moveTo(p point) } type firer interface { fire() }

Slide 52

Slide 52 text

Composition type vehicle struct { point passengers int } func (v *vehicle) moveTo(p point) { v.point = p } type weapon struct { loaded bool } func (w *weapon) fire() { w.loaded = false }

Slide 53

Slide 53 text

Composition type tank struct { vehicle weapon }

Slide 54

Slide 54 text

Composition type moverFirer interface { mover firer } func moveAndFire(mf moverFirer, p point) { mf.moveTo(p) mf.fire() }

Slide 55

Slide 55 text

Composition func main() { t := &tank{ vehicle{point{5, 6}, 6}, weapon{true}, } moveAndFire(t, point{10, 20}) fmt.Printf("Location: %v; Passengers: %d; Loaded: %t\n", t.point, t.passengers, t.loaded) // Location: {10 20}; Passengers: 6; Loaded: false }

Slide 56

Slide 56 text

Composition Composition is a design pattern discrete behaviours are defined through interfaces they are implemented via methods in concrete types Simple behaviours are composed to give complexity

Slide 57

Slide 57 text

Concurrency

Slide 58

Slide 58 text

Concurrency concurrency is not parallelism

Slide 59

Slide 59 text

Concurrency Go has concurrency primitives built-in: goroutines for concurrent functions channels for communicating between goroutines

Slide 60

Slide 60 text

Goroutines

Slide 61

Slide 61 text

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

Slide 62

Slide 62 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 63

Slide 63 text

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

Slide 64

Slide 64 text

goroutines go someFunc() // Concurrency!

Slide 65

Slide 65 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 66

Slide 66 text

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

Slide 67

Slide 67 text

Goroutines import "sync" func main() { var wg sync.WaitGroup wg.Add(1) go func() { // Do work... wg.Done() }() wg.Wait() }

Slide 68

Slide 68 text

GOroutines 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 69

Slide 69 text

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

Slide 70

Slide 70 text

Goroutines Create two anonymous functions: one that outputs integers from 1 to 100; the other from 100 to 1. Start each function as a goroutine. Use a WaitGroup to ensure that main() doesn't exit until the goroutines are done.

Slide 71

Slide 71 text

Goroutines A Goroutine is a function running independently Effectively Lightweight threads Multiplexed against one or more OS threads WaitGroups can be used to signal goroutine completion

Slide 72

Slide 72 text

Channels

Slide 73

Slide 73 text

Channels "Do not communicate by sharing memory; instead, share memory by communicating." -- https://golang.org/doc/effective_go.html

Slide 74

Slide 74 text

Channels ch := make(chan int) ch <- 42 // Send a value to the channel v := <-ch // Receive a value from ch

Slide 75

Slide 75 text

Channels Buffered vs. Unbuffered

Slide 76

Slide 76 text

Channels c1 := make(chan int) // Unbuffered c2 := make(chan int, 0) // Unbuffered c3 := make(chan int, 100) // Buffered

Slide 77

Slide 77 text

Unbuffered Channels Image from github.com/ardenlabs/gotraining

Slide 78

Slide 78 text

Buffered Channels Image from github.com/ardenlabs/gotraining

Slide 79

Slide 79 text

Channels c2 := make(chan int, 1) // A buffered channel c2 <- 42 v := <-c2

Slide 80

Slide 80 text

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

Slide 81

Slide 81 text

Channels func search(q string, server string) string { /* ... */ } func parallelSearch(q string, servers []string) string { res := make(chan string, 3) for _, s := range servers { go func(x string) { res <- search(q, x) }(s) } return <-res } servers := []string{"s1", "s2", "s3"} fmt.Println(parallelSearch("foo", servers))

Slide 82

Slide 82 text

Channels ch := make(chan int) close(ch) // Close the channel for writing v, ok := <-ch // Receive, testing for closure if !ok { fmt.Println("Channel closed!") }

Slide 83

Slide 83 text

Channels ch := make(chan int) // Read from channel until it is closed for i := range ch { fmt.Println(i) }

Slide 84

Slide 84 text

Channels var wg sync.WaitGroup func main() { court := make(chan struct{}) // An unbuffered channel. wg.Add(2) // Add two to the WG, one for each player. // Launch two players. go player("Serena", court) go player("Venus", court) court <- struct{}{} // Serve the "ball." wg.Wait() // Wait for the game to finish. }

Slide 85

Slide 85 text

Channels func player(name string, court chan struct{}) { for { ball := <-court fmt.Println(name, "hit the ball") court <- ball // Hit the ball back. } }

Slide 86

Slide 86 text

Channels func player(name string, court chan struct{}) { for { ball, ok := <-court if !ok { // If the channel was closed we won. fmt.Println(name, "won!") return } fmt.Println(name, "hit the ball") court <- ball // Hit the ball back. } }

Slide 87

Slide 87 text

Channels func player(name string, court chan struct{}) { for { // Receive step excluded... if rand.Intn(10) == 0 { // Decide if we missed the ball. fmt.Println(name, "missed the ball") close(court) // Close the channel to signal we lost. return } fmt.Println(name, "hit the ball") court <- ball // Hit the ball back. } }

Slide 88

Slide 88 text

Channels func player(name string, court chan struct{}) { defer wg.Done() for { // ... } }

Slide 89

Slide 89 text

Channels $ go run tennis.go Venus hit the ball Serena hit the ball Venus hit the ball Serena hit the ball Venus hit the ball Serena hit the ball Venus missed the ball Serena won!

Slide 90

Slide 90 text

Channels Create a channel representing a track, and a function representing a runner. Pass a baton between runners over the channel, and end the race when the fourth runner receives the baton.

Slide 91

Slide 91 text

Goroutines Channels are used to communicate between goroutines Avoids the need for locking around data structures Channels can be buffered or unbuffered Closing a channel can be used as a signalling mechanism

Slide 92

Slide 92 text

and finally...

Slide 93

Slide 93 text

What have we covered? OOP: interfaces, methods and embedding Concurrency: goroutines and channels

Slide 94

Slide 94 text

Next Steps https://tour.golang.org/ https://golang.org/doc/effective_go.html https://github.com/ardanlabs/gotraining https://github.com/golang/go/wiki

Slide 95

Slide 95 text

Next Steps

Slide 96

Slide 96 text

Feedback http:// bit.ly / g102-feedback

Slide 97

Slide 97 text

The end @timblair