Introduction to Go
School of Computing Science, Glasgow University
13 October 2014
Dave Cheney
Dave Cheney
This talk is an amalgam of a talk I gave to the Canberra Go users group
go-talks.appspot.com/github.com/davecheney/canberra-gophers/introduction-to-go.slide
and Robert Griesemer's "A Taste of Go"
go-talks.appspot.com/code.google.com/p/go.talks/2014/taste.slide
From which I borrowed much of the "Program elements" section as Robert's description of the language was much better than my attempt.
As this talk is a derivative, it continues to be licenced under the BSD licence that covers the Go project.
2Designed by programmers for programmers!
3Go started in 2007 by Rob Pike, Robert Griesemer, Ken Thompson.
Russ Cox and Ian Lance Taylor joined soon after.
There is a story that Go was designed while waiting for a C++ program to compile.
In reality, Go was a response to the many of the frustrations that Rob, Robert and Ken experienced with the languages in use at Google at that time; C++, Java, and Python.
Rob Pike's 2012 paper, Less is exponentially more gives an excellent overview of the environment that gave rise to Go.
4First public announcement November 10th, 2009. The Go Programming Language, 2009
Go is an open source project.
All the commits, code review, design, debate, etc, are all done in the open on a public mailing lists.
5Rapid iteration over the next 2.5 years
Go 1.0 was released on the 28th of March, 2012.
Go 1.0 marked a line in the sand
Stability
3 point releases so far; Go 1.1, 1.2, and 1.3.
The fourth, Go 1.4, is on target to ship in December.
Rough 6 month release cycle; 3 month change window, 3 month stabilisation.
Big ticket features are discussed before the change window opens.
Each release has bought incremental improvements in the compilers, the runtime, the garbage collector.
New platforms and new architectures added.
7package main import "fmt" func main() { fmt.Println("Hello, 世界!") }
package main import ( "fmt" "log" "net/http" ) func HelloServer(w http.ResponseWriter, req *http.Request) { log.Println(req.URL) fmt.Fprintf(w, "Hello, 世界!\nURL = %s\n", req.URL) } func main() { fmt.Println("please connect to localhost:7777/hello") http.HandleFunc("/hello", HelloServer) log.Fatal(http.ListenAndServe(":7777", nil)) }
const e = 2.71828182845904523536028747135266249775724709369995957496696763 const third = 1/3
const M64 int64 = 1<<20
const M = 1<<20
const big = 1<<100 / 1e30 // valid constant expression
Compiler complains if a constant doesn't fit where it is used.
11var x int var s, t string
var x int var s, t string = "foo", "bar" // multiple assignment var x = 42 // int var s, b = "foo", true // string, bool
x := 42 s, b := "foo", true
return &x
uint8 (byte), uint16, uint32, uint32, uint64, int8, int16, int32, int32 (rune), int64, float32, float64, complex64, complex128, uint, int, uintptr, bool, string, error // not so usual
array, struct, pointer, function, slice, map, channel
interface
[10]byte // array of 10 bytes
struct {
name string
left, right *Node
action func(*Node)
}
func(a, b, c int)
func(http.ResponseWriter, *http.Request) errortype Weekday int
type Point struct {
x, y int
}[]T // slice of T
Common slice operations:
len(s) s[i] s[i:j] append(s, x) // append element x to slice s and return new slice
&, and dereference, * operators.x := 1000 y := &x y += 4 // nope
map[K]V // map K -> V
Common map operations:
make(map[K]V) len(m) m[k] delete(m, k)
for key, value := range m {
// order of key sequence different each time
}a, b = b, a // swap
f, err = os.Open(filename)
if x < y {
return x
} else {
return y
}
switch day {
case Mon:
...
// break is implicit
case Tue, Wed:
...
}for syntaxfor {
// loop forever
}
range over arrays, slices, and maps
for i, num := range numbers { ... }
for city, pop := range population { ... }Not shown: break, goto, continue, fallthrough
19func Sin(x float64) float64 func AddScale(x, y int, f float64) int
func Write(data []byte) (written int, err error)
func Printf(format string, args ...interface{})var delta int
return func(x int) int { return x + delta }Methods are functions with a receiver parameter:
func (p Point) String() string { return fmt.Sprintf("(%d, %d)", p.x, p.y) }
The receiver binds the method to its base type (Point):
type Point struct { x, y int }
Methods are invoked via the usual dot notation:
// +build OMIT
package main
import "fmt"
// Point START OMIT
type Point struct {
x, y int
}
// Point END OMIT
// String START OMIT
func (p Point) String() string {
return fmt.Sprintf("(%d, %d)", p.x, p.y)
}
// String END OMIT
func main() { p := Point{2, 3} fmt.Println(p.String()) fmt.Println(Point{3, 5}.String()) }
For the Weekday type:
type Weekday int
Define String method on Weekday:
func (d Weekday) String() string { // ...
// +build OMIT
package main
import "fmt"
// type START OMIT
type Weekday int
// type END OMIT
const (
Mon Weekday = iota
Tue
Wed
Thu
Fri
Sat
Sun
)
var names = [...]string{"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"}
// String START OMIT
func (d Weekday) String() string { // ...
// String END OMIT
return names[d]
}
func main() { fmt.Println(Mon.String()) fmt.Println() for d := Mon; d <= Sun; d++ { fmt.Println(d.String()) } }
Method calls via non-interface types are statically dispatched.
22Examples:
interface{} // empty interface
interface {
String() string
}
interface {
Len() int
Swap(i, j int)
Less(i, j int) bool
}type Stringer interface { String() string }
Both Weekday and Point define a String method, so values of both can be assigned to
a variable of Stringer type:
// +build OMIT
package main
import "fmt"
type Point struct {
x, y int
}
func (p Point) String() string {
return fmt.Sprintf("(%d, %d)", p.x, p.y)
}
type Weekday int
const (
Mon Weekday = iota
Tue
Wed
Thu
Fri
Sat
Sun
)
var names = [...]string{"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"}
func (d Weekday) String() string { // ...
return names[d]
}
// Stringer START OMIT
type Stringer interface {
String() string
}
// Stringer END OMIT
func main() { var x Stringer x = Point{2, 3} fmt.Println("A", x.String()) x = Tue fmt.Println("B", x.String()) fmt.Println("C", Point{2, 3}) // fmt.Println knows about Stringer! fmt.Println("D", Tue) }
Method calls via interface types are dynamically dispatched ("virtual function call").
24go f() go f(x, y, ...)
func f(msg string, delay time.Duration) { for { fmt.Println(msg) time.Sleep(delay) } }
Function f is launched as 3 different goroutines, all running concurrently:
// +build OMIT
package main
import (
"fmt"
"time"
)
// f START OMIT
func f(msg string, delay time.Duration) {
for {
fmt.Println(msg)
time.Sleep(delay)
}
}
// f END OMIT
func main() { go f("A--", 300*time.Millisecond) go f("-B-", 500*time.Millisecond) go f("--C", 1100*time.Millisecond) time.Sleep(20 * time.Second) }
A channel type specifies a channel value type (and possibly a communication direction):
chan int chan<- string // send-only channel <-chan T // receive-only channel
A channel is a variable of channel type:
var ch chan int ch := make(chan int) // declare and initialize with newly made channel
A channel permits sending and receiving values:
ch <- 1 // send value 1 on channel ch x = <-ch // receive a value from channel ch (and assign to x)
Channel operations synchronize the communicating goroutines.
28Each goroutine sends its results via channel ch:
func f(msg string, delay time.Duration, ch chan string) { for { ch <- msg time.Sleep(delay) } }
The main goroutine receives (and prints) all results from the same channel:
// +build OMIT
package main
import (
"fmt"
"time"
)
// f START OMIT
func f(msg string, delay time.Duration, ch chan string) {
for {
ch <- msg
time.Sleep(delay)
}
}
// f END OMIT
func main() { ch := make(chan string) go f("A--", 300*time.Millisecond, ch) go f("-B-", 500*time.Millisecond, ch) go f("--C", 1100*time.Millisecond, ch) for i := 0; i < 100; i++ { fmt.Println(i, <-ch) } }
Packages you import are referenced by their package's prefix.
import "fmt"
func main() {
fmt.Printf("Hello %s\n", "world)
}Import cycles are not permitted.
30To a first order approximation, the std lib provides only the things needed to build Go itself.
32Cross platform is defined as the super set of all platforms with some not supporting a particular feature, rather than the lowest common denominator.
Two production compiler implementations
Other implementations, llgo, tardis-go, etc, keep us honest by writing to the spec.
33
/usr/bin/go
Simple, zero configuration, build tool.
All commands and paths are relative to your $GOPATH workspace.
Supports conditional compilation via suffixes and build tags.
Support for cross compilation.
GOARCH=386 GOOS=windows go build mycmd
Read package documentation
godoc $PKG
Lint your code
go vet $PKG
Solve code formatting issues, once and for all
go fmt $PKG
Built in testing framework, including benchmarking and coverage reports
go test $PKG go test -cover $PKG
Built in race detector (based on ThreadSantizer)
go {build,test,install} -race $PKGStart with the tour, tour.golang.org
Read Effective Go
Online communities
36This talk is online
talks.godoc.org/github.com/davecheney/presentations/introduction-to-go.slide
All the links inside the talk are clickable, I encourage you to follow them.
Also, please take the time to visit