$ go please
go please: unknown command
Run 'go help' for usage.

What you thought about Go

Or maybe

How it actually felt

func double(s []int) []int {
        b := s
        for i, v := range b {
                b[i] = 2 * v
        }
        return b
}

func main() {
        a := []int{3, 5, 8}
        b := double(a)
        fmt.Println(a)
        fmt.Println(b)
}

"A Slice of Betrayal"

func double(s []int) []int {
        b := s
        for i, v := range b {
                b[i] = 2 * v
        }
        return b
}

func main() {
        a := []int{3, 5, 8}
        b := double(a)
        fmt.Println(a)
        fmt.Println(b)
}

// >> [6 10 16]
// >> [6 10 16]

"A Slice of Betrayal"

"A Slice of Betrayal"

func double(s []int) []int {
        b := make([]int, len(s))
        copy(b, s)
        for i, v := range b {
                b[i] = 2 * v
        }
        return b
}

func main() {
        a := []int{3, 5, 8}
        b := double(a)
        fmt.Println(a)
        fmt.Println(b)
}

// >> [3 5 8]
// >> [6 10 16]

"A Slice of Betrayal"

func main() {
        x := make([]int, 5)
        for i := range x {
                x = append(x, i)
        }
        fmt.Println(x, cap(x), len(x))
}

"The Pit and the Append-ulum"

func main() {
        x := make([]int, 5)
        for i := range x {
                x = append(x, i)
        }
        fmt.Println(x, cap(x), len(x))
}

// >> [0 0 0 0 0 0 1 2 3 4] 10 10

"The Pit and the Append-ulum"

func main() {
        x := make([]int, 0, 5)
        for i := 0; i < 5; i++ {
                x = append(x, i)
        }
        fmt.Println(x, cap(x), len(x))
}

// >> [0 1 2 3 4] 5 5

"The Pit and the Append-ulum"

func main() {
        x := []int{}
        for i := 0; i < 5; i++ {
                x = append(x, i)
        }
        fmt.Println(x, cap(x), len(x))
}

// >> [0 1 2 3 4] 8 5

"The Pit and the Append-ulum"

func loadOne(c config) error {
        return errors.New("load one failed: bad config")
}

func initialize(typ string) (err error) {
        switch typ {
        case "one":
                x, err := getOneConfig()
                if err != nil {
                        fmt.Println(err)
                }
                err = loadOne(x)
        case "two":
                err = loadTwo()
        }
        return
}

func main() {
        fmt.Println(initialize("one"))
}

"Shadows in the Dark"

func initialize(typ string) (err error) {
        switch typ {
        case "one":
                x, err := getOneConfig()
                if err != nil {
                        fmt.Println(err)
                }
                err = loadOne(x)
        case "two":
                err = loadTwo()
        }
        return
}

func main() {
        fmt.Println(initialize("one"))
}

// >> <nil>

"Shadows in the Dark"

func initialize(typ string) (err error) {
        switch typ {
        case "one":
                var x oneConfig
                x, err = getOneConfig()
                if err != nil {
                        fmt.Println(err)
                }
                err = loadOne(x)
        case "two":
                err = loadTwo()
        }
        return err
}

func main() {
        fmt.Println(initialize("one"))
}

// >> load one failed: bad config

"Shadows in the Dark"

"Shadows in the Dark"

go vet -shadow

go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow
go vet -vettool=$(which shadow)
type ErrEx struct{}

func (*ErrEx) Error() string {
        return "failed"
}

func execute() *ErrEx {
        return nil
}

func main() {
        var err error
        err = execute()
        if err != nil {
                fmt.Println("😱")
        } else {
                fmt.Println("😎")
        }
}

"To Err is Human"

type ErrEx struct{}

func (*ErrEx) Error() string {
        return "failed"
}

func execute() *ErrEx {
        return nil
}

func main() {
        var err error
        err = execute()
        if err != nil {
                fmt.Println("😱")
        } else {
                fmt.Println("😎")
        }
}

// >> 😱

"To Err is Human"

"To Err is Human"

type ErrEx struct{}

func (*ErrEx) Error() string {
        return "failed"
}

func execute() error {
        return nil
}

func main() {
        var err error
        err = execute()
        if err != nil {
                fmt.Println("😱")
        } else {
                fmt.Println("😎")
        }
}

// >> 😎

"To Err is Human"

func main() {
        for i := 0; i < 5; i++ {
                go func() {
                        fmt.Println(i)
                }()
        }
}

"Merry Go Round"

func main() {
        for i := 0; i < 5; i++ {
                go func() {
                        fmt.Println(i)
                }()
        }
}

// >>
// echo $?
// >> 0

"Merry Go Round"

func main() {
        var wg sync.WaitGroup
        for i := 0; i < 5; i++ {
                wg.Add(1)
                go func() {
                        fmt.Println(i)
                        wg.Done()
                }()
        }
        wg.Wait()
}

"Merry Go Round"

func main() {
        var wg sync.WaitGroup
        for i := 0; i < 5; i++ {
                wg.Add(1)
                go func() {
                        fmt.Println(i)
                        wg.Done()
                }()
        }
        wg.Wait()
}

// >> 5
// >> 5
// >> 5
// >> 5
// >> 5

"Merry Go Round"

func main() {
        var wg sync.WaitGroup
        for i := 0; i < 5; i++ {
                wg.Add(1)
                go func(local int) {
                        fmt.Println(local)
                        wg.Done()
                }(i)
        }
        wg.Wait()
}

// >> 4
// >> 0
// >> 2
// >> 1
// >> 3

"Merry Go Round"

func theLongNight() (ret string) {
        defer func() {
                fmt.Println(ret)
                ret = "🦌"
        }()
        defer func() {
                fmt.Println(ret)
                ret = "🐺"
        }()
        ret = "🐲"
        return "🦁"
}

func main() {
        fmt.Println(theLongNight())
}

"Game of Throws"

func theLongNight() (ret string) {
        defer func() {
                fmt.Println(ret)
                ret = "🦌"
        }()
        defer func() {
                fmt.Println(ret)
                ret = "🐺"
        }()
        ret = "🐲"
        return "🦁"
}

func main() {
        fmt.Println(theLongNight())
}

// >> 🦁
// >> 🐺
// >> 🦌

"Game of Throws"

type Vampire struct {
        name string `json:"name"`
        age  int    `json:"age"`
}

func main() {
        d := json.NewDecoder(os.Stdin)
        var vamps Vampire
        err := d.Decode(&vamps)
        if err != nil {
                fmt.Println("😱")
        }
        fmt.Println(vamps)
}

"Shifty Serialization"

type Vampire struct {
        name string `json:"name"`
        age  int    `json:"age"`
}

func main() {
        d := json.NewDecoder(os.Stdin)
        var vamps Vampire
        err := d.Decode(&vamps)
        if err != nil {
                fmt.Println("😱")
        }
        fmt.Printf("%+v\n", vamps)
}

// << {"name": "Dracula", "age": 102}
// >> {name: age:0}

"Shifty Serialization"

type Vampire struct {
        Name string `json:"name"`
        Age  int    `json:"age"`
}

func main() {
        d := json.NewDecoder(os.Stdin)
        var vamps Vampire
        err := d.Decode(&vamps)
        if err != nil {
                fmt.Println("😱")
        }
        fmt.Printf("%+v\n", vamps)
}

// << {"name": "Dracula", "age": 102}
// >> {Name:Dracula Age:102}

"Shifty Serialization"

type ConnWrapper struct {
        conn string
}

func (cw ConnWrapper) Wrap(c string) {
        cw.conn = c
}

func (cw ConnWrapper) Read() string {
        return cw.conn
}

func main() {
        cw := ConnWrapper{"initial-host:80"}
        cw.Wrap("redirect-host:8080")
        fmt.Println(cw.Read())
}

"Value Receiver"

type ConnWrapper struct {
        conn string
}

func (cw ConnWrapper) Wrap(c string) {
        cw.conn = c
}

func (cw ConnWrapper) Read() string {
        return cw.conn
}

func main() {
        cw := ConnWrapper{"initial-host:80"}
        cw.Wrap("redirect-host:8080")
        fmt.Println(cw.Read())
}

// >> initial-host:80

"Value Receiver"

type ConnWrapper struct {
        conn string
}

func (cw *ConnWrapper) Wrap(c string) {
        cw.conn = c
}

func (cw *ConnWrapper) Read() string {
        return cw.conn
}

func main() {
        cw := ConnWrapper{"initial-host:80"}
        cw.Wrap("redirect-host:8080")
        fmt.Println(cw.Read())
}

// >> redirect-host:8080

"Pointer Receiver"

func main() {
        var cache map[string]string
        x := cache["0xdeadbeef"]
        fmt.Println(x)
        cache["0x5ca1ab1e"] = "webscale"
        fmt.Println(cache)
}

"Treasure Map"

func main() {
        var cache map[string]string
        x := cache["0xdeadbeef"]
        fmt.Println(x)
        cache["0x5ca1ab1e"] = "webscale"
        fmt.Println(cache)
}

// >> panic: assignment to entry in nil map
// >> 
// >> goroutine 1 [running]:
// >> main.main()
// >>         map_initialization.go:9 +0xf8
// >> exit status 2

"Treasure Map"

func main() {
        cache := map[string]string{}
        x := cache["0xdeadbeef"]
        fmt.Println(x)
        cache["0x5ca1ab1e"] = "webscale"
        fmt.Println(cache)
}

func main() {
        cache := make(map[string]string)
        x := cache["0xdeadbeef"]
        fmt.Println(x)
        cache["0x5ca1ab1e"] = "webscale"
        fmt.Println(cache)
}

// >> 
// >> map[0x5ca1ab1e:webscale]

"Treasure Map"

var cache = make(map[string]string)

func get(w http.ResponseWriter, r *http.Request) {
        k := r.URL.Query().Get("key")
        w.Write([]byte(cache[k]))
}

func set(w http.ResponseWriter, r *http.Request) {
        k := r.URL.Query().Get("key")
        v := r.URL.Query().Get("val")
        cache[k] = v
}

func main() {
        http.HandleFunc("/set", set)
        http.HandleFunc("/get", get)
        http.ListenAndServe(":8080", nil)
}

"Concurrent Treasure Map"

var cache = make(map[string]string)
var lock = sync.RWMutex{}

func get(w http.ResponseWriter, r *http.Request) {
        k := r.URL.Query().Get("key")
        lock.RLock()
        w.Write([]byte(cache[k]))
        lock.RUnlock()
}

func set(w http.ResponseWriter, r *http.Request) {
        k := r.URL.Query().Get("key")
        v := r.URL.Query().Get("val")
        lock.Lock()
        cache[k] = v
        lock.Unlock()
}

"Concurrent Treasure Map"

func main() {
        b := make(chan struct{})
        b <- struct{}{}
        <-b
        fmt.Println("okay")
}

"Think you're buff?"

func main() {
        b := make(chan struct{})
        b <- struct{}{}
        <-b
        fmt.Println("okay")
}

// >> fatal error: all goroutines are asleep - deadlock!
// >> 
// >> goroutine 1 [chan send]:
// >> main.main()
// >>         chan_unbuf.go:7 +0x57
// >> exit status 2

"Think you're buff?"

func main() {
        b := make(chan struct{}, 1)
        b <- struct{}{}
        <-b
        fmt.Println("okay")
}

"Think you're buff?"

func main() {
        b := make(chan struct{}, 1)
        b <- struct{}{}
        <-b
        fmt.Println("okay")
}

// >> okay

"Think you're buff?"

func main() {
        x := make(chan int, 1)
        y := make(chan int, 1)
        z := make(chan int, 1)
        x <- 1
        y <- 2
        z <- 3
        select {
        case <-x:
                fmt.Println("read x")
        case <-y:
                fmt.Println("read y")
        case <-z:
                fmt.Println("read z")
        }
}

"Select *"

func main() {
        x := make(chan int, 1)
        y := make(chan int, 1)
        z := make(chan int, 1)
        x <- 1
        y <- 2
        z <- 3
        select {
        case <-x:
                fmt.Println("read x")
        case <-y:
                fmt.Println("read y")
        case <-z:
                fmt.Println("read z")
        }
}

// >> read y

"Select *"

func main() {
        x := make(chan int, 1)
        y := make(chan int, 1)
        z := make(chan int, 1)
        x <- 1
        y <- 2
        z <- 3
        select {
        case <-x:
                fmt.Println("read x")
        case <-y:
                fmt.Println("read y")
        case <-z:
                fmt.Println("read z")
        }
}

// >> read y
// >> read z

"Select *"

func main() {
        x := make(chan int, 1)
        y := make(chan int, 1)
        z := make(chan int, 1)
        x <- 1
        y <- 2
        z <- 3
        select {
        case <-x:
                fmt.Println("read x")
        case <-y:
                fmt.Println("read y")
        case <-z:
                fmt.Println("read z")
        }
}

// >> read y
// >> read z
// >> read y

"Select *"

func main() {
        x := make(chan int)
        go func() {
                x <- 1
        }()
        select {
        case <-x:
                fmt.Println("read x")
        default:
                fmt.Println("default")
        }
}

"Select *"

func main() {
        x := make(chan int)
        go func() {
                x <- 1
        }()
        select {
        case <-x:
                fmt.Println("read x")
        default:
                fmt.Println("default")
        }
}

// >> default

"Select *"

func main() {
        x := make(chan int)
        go func() {
                x <- 1
        }()
        select {
        case <-x:
                fmt.Println("read x")
        default:
                fmt.Println("default")
        }
}

// >> default
// >> default

"Select *"

func main() {
        x := make(chan int)
        go func() {
                x <- 1
        }()
        select {
        case <-x:
                fmt.Println("read x")
        default:
                fmt.Println("default")
        }
}

// >> default
// >> default
// >> default

"Select *"

func main() {
        x := make(chan int)
        go func() {
                x <- 1
        }()
        time.Sleep(10*time.Millisecond)
        select {
        case <-x:
                fmt.Println("read x")
        default:
                fmt.Println("default")
        }
}

// >> read x

"Select *"

func main() {
        x := make(chan int)
        go func() {
                x <- 1
        }()
        time.Sleep(10*time.Millisecond)
        select {
        case <-x:
                fmt.Println("read x")
        default:
                fmt.Println("default")
        }
}

// >> read x
// >> read x

"Select *"

"Select *"

  • Vet your code
  • Test your code
  • See weird behavior?
    • Look to the spec
  • Ask in #golang

go please

By Alan Braithwaite

go please

  • 56
Loading comments...

More from Alan Braithwaite