Pro Yearly is on sale from $80 to $50! »

Go 102: A Workshop

2a32a8864a24ef5c1ce26260d5eebdd6?s=47 timblair
November 26, 2015

Go 102: A Workshop

This is the slide deck to accompany the workshop I gave on 2015-11-26. The content covers:

* A quick introduction: built-in types, variable declaration, function and custom types.
* Object oriented development: methods, interfaces, embedding and composition.
* Concurrency: goroutines and channels.

Each section ended with a hands-on exercise to apply the information from that section. The detailed material from the workshop (including the exercises) is available at: https://github.com/timblair/go-102

2a32a8864a24ef5c1ce26260d5eebdd6?s=128

timblair

November 26, 2015
Tweet

Transcript

  1. Go 102 A Go Workshop

  2. Topics Go Basics Object Oriented Programming in Go Concurrency

  3. Information / timblair / go-102-workshop

  4. The Basics

  5. The Language Designed for concurrent systems programming, Strongly and statically

    typed, Compiled, Garbage collected, Object oriented (ish), Small, opinionated, and done.
  6. Hello World package main import ( "fmt" ) func main()

    { fmt.Println("Hello, World!") }
  7. Types Arrays slices maps booleans numerics strings pointers structs channels

  8. Types Arrays slices maps booleans numerics strings pointers structs channels

  9. 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"
  10. 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
  11. Zero Values 0 // numeric false // boolean "" //

    string nil // pointer, channel, func, // interface, map, or slice
  12. 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
  13. 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" }
  14. 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.
  15. What have we covered? Built-in Types & value declaration All

    types have a zero value structs as collections of named fields functions
  16. Object Orientation

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

  18. Object Orientation Abstraction Encapsulation Inheritance Polymorphism

  19. Object Orientation OOP is about objects. An object is a

    data structure that has both state and behaviour
  20. Methods

  21. 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 }
  22. Methods A method is a function bound to a receiver

  23. 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 }
  24. Methods A receiver can be any named type

  25. 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 }
  26. 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.
  27. Methods methods are functions that are bound to a receiver

    A receiver can be any named type Methods are effectively syntactic sugar
  28. Interfaces

  29. Interfaces Provide polymorphism Declare behaviour

  30. Interfaces no implements keyword interfaces are satisfied implicitly

  31. Interfaces type speaker interface { speak() string }

  32. 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() { /* ... */ }
  33. 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
  34. Interfaces type email struct { name string address string }

    e := email{"Tim Blair", "tim@bla.ir"} fmt.Println(e) // {Tim Blair tim@bla.ir}
  35. Interfaces // The Stringer interface found in fmt package type

    Stringer interface { String() string }
  36. 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", "tim@bla.ir"} fmt.Println(e) // "Tim Blair" <tim@bla.ir>
  37. 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.
  38. Interfaces Interfaces are types that declare behaviour they provide polymorphism

    behaviour no `implements` keyword; satisfied implicitly
  39. Embedding

  40. Embedding type sphere struct { x, y, z, radius int

    } type cube struct { x, y, z, length int }
  41. 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
  42. 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
  43. Embedding s1 := sphere{point{1, 2, 3}, 5} s2 := sphere{

    point: point{ 1, 2, 3, }, radius: 5, // required trailing comma }
  44. Embedding type robot struct { } func (r robot) talk()

    { fmt.Println("Bzzzzzbt") } type robby struct { robot } robby := robby{} robby.talk() // Bzzzzzbt
  45. 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?
  46. 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{})
  47. 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.
  48. 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
  49. Composition

  50. Composition "Everyone knows composition is more powerful than inheritance, Go

    just makes this non optional." –– Dave Cheney: http://bit.ly/dctlg
  51. Composition type point struct { x, y int } type

    mover interface { moveTo(p point) } type firer interface { fire() }
  52. 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 }
  53. Composition type tank struct { vehicle weapon }

  54. Composition type moverFirer interface { mover firer } func moveAndFire(mf

    moverFirer, p point) { mf.moveTo(p) mf.fire() }
  55. 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 }
  56. 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
  57. Concurrency

  58. Concurrency concurrency is not parallelism

  59. Concurrency Go has concurrency primitives built-in: goroutines for concurrent functions

    channels for communicating between goroutines
  60. Goroutines

  61. Goroutines Lightweight threads of execution multiplexed across os threads very

    cheap to use
  62. goroutines func doWork(i int) { time.Sleep(time.Millisecond * 500) fmt.Println(i) }

    func main() { for i := 1; i <= 5; i++ { doWork(i) } }
  63. goroutines $ time go run g1.go 1 2 3 4

    5 go run g1.go ... 2.757 total
  64. goroutines go someFunc() // Concurrency!

  65. 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! } }
  66. goroutines $ time go run g2.go go run g2.go ...

    0.247 total
  67. Goroutines import "sync" func main() { var wg sync.WaitGroup wg.Add(1)

    go func() { // Do work... wg.Done() }() wg.Wait() }
  68. 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() }
  69. goroutines $ time go run g3.go 4 1 5 2

    3 go run g3.go ... 0.752 total
  70. 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.
  71. 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
  72. Channels

  73. Channels "Do not communicate by sharing memory; instead, share memory

    by communicating." -- https://golang.org/doc/effective_go.html
  74. Channels ch := make(chan int) ch <- 42 // Send

    a value to the channel v := <-ch // Receive a value from ch
  75. Channels Buffered vs. Unbuffered

  76. Channels c1 := make(chan int) // Unbuffered c2 := make(chan

    int, 0) // Unbuffered c3 := make(chan int, 100) // Buffered
  77. Unbuffered Channels Image from github.com/ardenlabs/gotraining

  78. Buffered Channels Image from github.com/ardenlabs/gotraining

  79. Channels c2 := make(chan int, 1) // A buffered channel

    c2 <- 42 v := <-c2
  80. 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 }
  81. 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))
  82. 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!") }
  83. Channels ch := make(chan int) // Read from channel until

    it is closed for i := range ch { fmt.Println(i) }
  84. 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. }
  85. Channels func player(name string, court chan struct{}) { for {

    ball := <-court fmt.Println(name, "hit the ball") court <- ball // Hit the ball back. } }
  86. 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. } }
  87. 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. } }
  88. Channels func player(name string, court chan struct{}) { defer wg.Done()

    for { // ... } }
  89. 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!
  90. 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.
  91. 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
  92. and finally...

  93. What have we covered? OOP: interfaces, methods and embedding Concurrency:

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

  95. Next Steps

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

  97. The end @timblair