golang

an intro*

slides.com/wmv/go/live

*  (superficial)

Go is not meant to innovate programming theory. It’s meant to innovate programming practice.

Samuel Tesla

  • Sep  2007R Griesemer, R Pike, K Thompson dream up GO

  • Nov 2009GO officially announced

  • May 2010Start of GO internal use @ Google

  • Mar 2012GO v1 is released

not a very old language at all!

Some background...

Authors:

  • Robert Griesemer: JVM, JS v8 engine
  • Rob Pike: Unix, Plan9, Inferno, UTF-8
  • Ken Thompson: B, C, Unix, Plan9, UTF-8
  • Russ Cox: libtask for Unix

why go?

  • productivity of Python / Ruby
  • performance of C/C++

why go?

 

it's designed to help write big programs, written and maintained by big teams.

why go?

  • lightweight, avoids unnecessary repetition
  • object oriented (via types and interfaces)
  • designed for working programmers
  • very small core. Easy to remember all of it.

why go?

  • compiled. No, cross-compiled!
  • statically typed
  • garbage-collected
  • batteries included

why go?

... why stay ?

Satisfied Customers:

  • Google
  • BBC
  • Heroku
  • CloudFoundry
  • CloudFlare
  • Bit.ly
  • Iron.io

 

Lots of big players like it!

Getting Started:

  1. golang.org/doc/install
  2. set up $GOPATH
  3. pick an IDE
  4. go write some code!
$ mkdir $HOME/go
$ export GOPATH=$HOME/go
$ export PATH=$PATH:$GOPATH/bin

Pick an IDE:

  • Sublime Text
  • IntelliJ
  • LintelIDE
  • Intype
  • NetBeans
  • TextMate
  • Komodo
  • Zeus

 

( ... vim/emacs have great support too )

hello, Go!

package main

import "fmt"

func main() {
        // Kon'nichiwa!
	fmt.Println("こんにちわ, Go!")
}

vars, looping

package main

import (
    "fmt"
)

func main() {
    a, b := 1, 2
    fmt.Printf("a + b: %d\n", a + b)

    for a < 100 {
        a++
        fmt.Println(a)
    }
}

imports, casting

package main

import (
    "fmt"
    "math"
)

func main() {
    for i := 0; i < 100; i++ {
        fmt.Println(math.Pow(float64(i), 2))
    }
}

hello, http!

package main

import (
	"fmt"
	"net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Printf("Hey! New request!")
}

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

( funcs )

  • Same syntax for methods, anonymous functions & closures

  • main.main() is the function run when the program is executed

main.main()

  • No void

  • No return value

  • No function args 
 (command line is in os package) 

"packages"

  • Not classes or objects

  • No subpackages

  • Fundamental building block in Go

  • Programs run “main” package

  • Package path is just 
 a string (allows for URLs)

  • Standard library sits at the root (no path) 

  • private vs Public functions, types, etc =
    = Caps vs noCaps

flow control

Loop types in go:

  • for
  • for
  • for

A simple "For"...

package main

import "fmt"

func main() {
	for i := 1;  i<=5; i++ {
                fmt.Printf("Welcome %d times\n",i)
        }
}

(similar to Java, C)

Becomes a "While"...

package main

import "fmt"

func main() {
	sum := 1
	for ; sum < 1000; {            // No pre or post
		sum += sum
	}
	fmt.Println(sum)
}

As in C or Java, you can leave the pre and post statements empty.

Look ma, no semicolons

package main

import "fmt"

func main() {
	sum := 1
	for sum < 1000 {            // No semicolons
		sum += sum
	}
	fmt.Println(sum)
}

∞ 

package main

func main() {
	for {     // Runs forever!
	}
}

(while true)

if conditions are omitted, block loops forever

IF

package main

import "fmt"

func main() {

    // Here's a basic example.
    if 7%2 == 0 {
        fmt.Println("7 is even")
    } else {
        fmt.Println("7 is odd")
    }

    // You can have an `if` statement without an else.
    if 8%4 == 0 {
        fmt.Println("8 is divisible by 4")
    }

    // A statement can precede conditionals; any variables
    // declared in this statement are available in all
    // branches.
    if num := 9; num < 0 {
        fmt.Println(num, "is negative")
    } else if num < 10 {
        fmt.Println(num, "has 1 digit")
    } else {
        fmt.Println(num, "has multiple digits")

SWITCH

// _Switch statements_ express conditionals across many
// branches.

package main

import "fmt"
import "time"

func main() {

    // Here's a basic `switch`.
    i := 2
    fmt.Print("write ", i, " as ")
    switch i {
    case 1:
        fmt.Println("one")
    case 2:
        fmt.Println("two")
    case 3:
        fmt.Println("three")
    }

    // You can use commas to separate multiple expressions
    // in the same `case` statement. We use the optional
    // `default` case in this example as well.
    switch time.Now().Weekday() {
    case time.Saturday, time.Sunday:
        fmt.Println("it's the weekend")
    default:
        fmt.Println("it's a weekday")
package main

import (
	"fmt"
	"runtime"
)

func main() {
	fmt.Print("Go runs on ")
	switch os := runtime.GOOS; os {
	case "darwin":
		fmt.Println("OS X.")
	case "linux":
		fmt.Println("Linux.")
	default:
		// freebsd, openbsd,
		// plan9, windows...
		fmt.Printf("%s.", os)
	}
}

SWITCH

What's your OS?

package main

import "fmt"

func main() {
	defer fmt.Println("World!")

	fmt.Println("Hello, ")
}

DEFER

package main

import "fmt"

func main() {
	defer func1()
	defer func2()
	defer func3()
	defer func4()

	fmt.Println("Check out how these execute:")
}

func func1() {
	print("Outer Func\n")
}

func func2() {
	print("1 level in\n")
}

func func3() {
	print("2 levels in\n")
}

func func4() {
	print("3 levels in\n")
}

DEFER

Stack

(LIFO)

package main

import "fmt"

func main() {
	letters := []string{"Aa", "Bb", "Cc", "Dd", "Ee"}
	for i, v := range letters {
		fmt.Printf("%d = %s\n", i, v)
	}
}

RANGE

package main

import "fmt"

func f(from string) {
    for i := 0; i < 3; i++ {
        fmt.Println(from, ":", i)
    }
}

func main() {

    // Suppose we have a function call `f(s)`. Here's how
    // we'd call that in the usual way, running it
    // synchronously.
    f("direct")

    // To invoke this function in a goroutine, use
    // `go f(s)`. This new goroutine will execute
    // concurrently with the calling one.
    go f("goroutine")

    // You can also start a goroutine for an anonymous
    // function call.
    go func(msg string) {
        fmt.Println(msg)
    }("going")

GOROUTINES

A goroutine is a lightweight thread of execution.

 

<- channels <-

  • Channels are the pipes that connect concurrent goroutines.

  • You can send values into channels from one goroutine and receive those values into another goroutine.

  • A channel type is represented with the keyword chan followed by the type of the things that are passed on the channel

  • The <- (left arrow) operator is used to send and receive messages on the channel.


package main

import "fmt"

func main() {

    // Create a new channel with `make(chan val-type)`.
    // Channels are typed by the values they convey.
    messages := make(chan string)

    // _Send_ a value into a channel using the `channel <-`
    // syntax. Here we send `"ping"`  to the `messages`
    // channel we made above, from a new goroutine.
    go func() { messages <- "ping" }()

    // The `<-channel` syntax _receives_ a value from the
    // channel. Here we'll receive the `"ping"` message
    // we sent above and print it out.
    msg := <-messages
    fmt.Println(msg)
}

CHANNELS

OOPs!

* Pointers *

  • & in front of variable name is used to retrieve the address of where this variable’s value is stored. That address is what the pointer is going to store.

  • * in front of a variable of pointer type is used to retrieve a value stored at given address. In Go speak this is called dereferencing.

  • * in front of a type name, means that the declared variable will store an address of another variable of that type (not a value of that type).

package main

import "fmt"

func main() {
	i, j := 42, 2701

	p := &i         // point to i
	fmt.Println(*p) // read i through the pointer
	*p = 21         // set i through the pointer
	fmt.Println(i)  // see the new value of i

	p = &j         // point to j
	*p = *p / 37   // divide j through the pointer
	fmt.Println(j) // see the new value of j
}

POINTERS

{ Structs }

  • a collection of fields
  • as close as one gets to Classes in GO
  • can have methods assigned to them
    (by defining a func with a 
    “receiver” )
package main

import "fmt"

type Vertex struct {
	X int
	Y int
}

func main() {
	v := Vertex{1, 2}
	v.X = 4
	fmt.Println(v.X)
}

STRUCTS

{ Interfaces }

  • named collections of method signatures.
  • To implement an interface in Go, we just need to implement all the methods in the interface.
  • Like a struct, an interface is created using the type keyword, followed by a name and the keyword interface. But instead of defining fields, we define a “method set”. A method set is a list of methods that a type must have in order to “implement” the interface.
package main
import "fmt"
import "math"
type geometry interface {
    area() float64
    perim() float64
}
type square struct {
    width, height float64
}
type circle struct {
    radius float64
}
func (s square) area() float64 {
    return s.width * s.height
}
func (s square) perim() float64 {
    return 2*s.width + 2*s.height
}
func (c circle) area() float64 {
    return math.Pi * c.radius * c.radius
}
func (c circle) perim() float64 {
    return 2 * math.Pi * c.radius
}
func measure(g geometry) {
    fmt.Println(g)
    fmt.Println(g.area())
    fmt.Println(g.perim())
}
func main() {
    s := square{width: 3, height: 4}
    c := circle{radius: 5}
    measure(s)
    measure(c)
}

INTERFACES

more on OOP:

[ Arrays and Slices ]

  • An array's length is part of its type, so arrays cannot be resized. 

  • Mostly interacted with upon instantiation only.

  • An array is not a slice.

  • The slice type is an abstraction built on top of Go's array type

  • A slice points to an array of values and also includes a length.

  • ​It is common to append new elements to a slice, and so Go provides a built-in append function.

TL;DR:

You’ll see slices much more often than arrays in typical Go. 

Arrays have their place, but they're a bit inflexible, so you don't see them too often in Go code. Slices, though, are everywhere. They build on arrays to provide great power and convenience.

An array literal can be specified like so:

 
b := [2]string{"Penn", "Teller"}

A slice literal is declared just like an array literal, except you leave out the element count:

 
letters := []string{"a", "b", "c", "d"}

This is also the syntax to create a slice given an array:

 

 
x := [3]string{"Лайка", "Белка", "Стрелка"}
s := x[:] // a slice referencing the storage of x
package main

import "fmt"

func main() {
	var a [2]string
	a[0] = "Hello"
	a[1] = "World"
	fmt.Println(a[0], a[1])
	fmt.Println(a)
}

ARRAYS

Tip: The type [n]T is an array of n values of type T.

package main

import "fmt"

func main() {
	p := []int{2, 3, 5, 7, 11, 13}
	fmt.Println("p ==", p)

	for i := 0; i < len(p); i++ {
		fmt.Printf("p[%d] == %d\n", i, p[i])
	}
}

SLICES

Tip: The length and capacity of a slice can be inspected using the built-in len and cap functions.

package main

import "fmt"

func main() {

	var timeZone = map[string]int{
		"UTC": 0,
		"EST": -5,
		"CST": -6,
		"MST": -7,
		"PST": -8,
	}
	fmt.Println(timeZone["EST"])

	timeZone2 := make(map[string]int)
	timeZone2["XST"] = 4
	fmt.Println(timeZone2["XST"])
}

MAPS

Maps are Go’s built-in associative data type (similar to python dicts).

ERRORS. inevitable?

  • Unlike some languages which use exceptions for handling of many errors, in Go it is idiomatic to use error-indicating return values wherever possible.
  • Go’s approach makes it easy to see which functions return errors and to handle them using the same language constructs employed for any other, non-error tasks.

Errors contd

  • By convention, errors are the last return value and have type error, a built-in interface.

  • A nil value in the error position indicates that there was no error.

ToolBox

  • go build builds Go binaries 
  • go test unit tests and microbenchmarks
  • go fmt formats code
  • go get retrieves and installs remote packages
  • go vet looks for potential errors in code
  • go run builds and executes code
  • godoc displays documentation or serves it via HTTP
  • gorename renames vars, funcs, etc in a type-safe way
  • go generate invokes code generators

go syntax highlights

  • Very minimal
  • Only "for" loop is used
  • Multiple return values
  • Named returns
  • Pointers
  • No exceptions

“Why would you have a language that is not theoretically exciting? Because it’s very useful.”

 

— Rob Pike

What interests You?

Resources:

www.golang-book.com

tour.golang.org

blog.golang.org

talks.golang.org

spf13.com/presentation/go-for-object-oriented-programmers

gobyexample.com

http://commandcenter.blogspot.com/

 

this deck: slides.com/wmv/go

 

https://gist.github.com/wmv/1c62bcacbf20f4621daf

thanks! :)

to IO (http://io.co.za/) - they are awesome!

Questions?

Wilson Canda

 

twitter.com/__wmv__

wilson.canda.me

 

dev @ wumdrop.com

illustrations here are mostly by Renée French

click to tweet:

go-intro

By Wilson Canda

go-intro

Gentle introduction to golang, prepared for a GDG Cape Town meetup.

  • 1,074