- Go is a programming language created at Google. It is fast, statically typed, and has garbage collection.
- The tutorial covers Go's history, why it was created, library support, and provides examples of variables, functions, flow control, methods, interfaces, and goroutines.
- The document includes an outline, code examples throughout to demonstrate the concepts, and references additional resources for learning Go.
6. History
● From Google!
○ The guys at Plan 9 from Bell Labs
● Current Version 1.1.2, still being actively
developed
7. Why Go!
● Fast
○ Almost as fast as C
○ Faster than C in some cases
● A small language
● Statically-typed
● Garbage Collection
● Easy to write/learn
● Reflection
8. How fast is Go?
From Computer Language Benchmark Game
9. Who use Go?
● Google, of course
● Google App Engine also supports Go!
10. Library Support
● A lot of built-in support including:
○ Containers: container/heap, container/list
○ Web server: net/http
○ Cryptography: crypto/md5, crypto/sha1
○ Compression: compress/gzip
○ Database: database/sql
11. Third-Party Libraries
● Gorilla: Web Framework
● go-qt: Qt binding for Go
● go-gtk3: Gtk3 binding for Go
● go-opengl: OpenGL binding for Go
● go:ngine: Go 3D Engine
● mgo: MongoDB binding for go
Tons more at:
https://code.google.com/p/go-wiki/wiki/Projects
13. Using Package
package main
import (
"fmt"
"math/rand"
)
func main() {
fmt.Println("My favorite number is",
rand.Intn(10))
}
You can also import package with separated line
import "fmt"
import "math/rand"
14. ● In Go, a name is exported if it begins with
capital letter. That is, you should use
instead of
Exported Names
fmt.Println("My favorite number is", rand.
Intn(10))
fmt.println("My favorite number is", rand.
Intn(10))
15. Variables
package main
import "fmt"
var x, y, z int
func main() {
var c, python, java = true, false, "no!"
haskell, racket, sml := true, true, false
fmt.Println(x, y, z, c, python, java,
haskell, racket, sml)
}
type can be omitted, since compiler
can guess it from the initializer
using the := construct, we can omit the
var keyword and type!
16. Basic Types
● bool
● string
● int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
● byte // alias for uint8
● rune // alias for int32
// represents a Unicode code point
● float32 float64
● complex64 complex128
var c complex128 = 1 + 2i
17. Constants
package main
import "fmt"
const Pi = 3.14
func main() {
const World = "世界"
fmt.Println("Hello", World)
fmt.Println("Happy", Pi, "Day")
const Truth = true
fmt.Println("Go rules?", Truth)
}
18. Grouping Variable and Constants
var (
ToBe bool = false
MaxInt uint64 = 1<<64 - 1
z complex128 = cmplx.Sqrt(-5 + 12i)
)
const (
Big = 1 << 100
Small = Big >> 99
)
19. Functions
package main
import "fmt"
func add(x int, y int) int {
return x + y
}
func add_and_sub(x, y int) (int, int) {
return x + y, x -y
}
func main() {
fmt.Println(add(42, 13))
a, b := add_and_sub(42, 13)
fmt.Println(a, b)
}
paramter name type return type
x, y share the same type multiple return value
receiving multiple reutrn value
20. Functions - Named results
package main
import "fmt"
func split(sum int) (x, y int) {
x = sum * 4 / 9
y = sum - x
return
}
func main() {
fmt.Println(split(17))
}
21. Functions are First Class Citizens
func main() {
hypot := func(x, y float64) float64 {
return math.Sqrt(x*x + y*y)
}
fmt.Println(hypot(3, 4))
}
Functions in Go are first class citizens, which means that you can
pass it around like values.
create a lambda(anonymous) function and assign it to
a variable
22. Closures
func adder() func(int) int {
sum := 0
return func(x int) int {
sum += x
return sum
}
}
Go uses lexical closures, which means a function is evaluated in the
environment where it is defined.
sum is accessible inside the
anonymous function!
23. For loop
func main() {
sum := 0
for i := 0; i < 10; i++ {
sum += i
}
for ; sum < 1000; {
sum += sum
}
for sum < 10000 {
sum += sum
}
fmt.Println(sum)
for {
}
}
Go does not have while loop!
while loops are for loops!
Infinite loop!
similar to C but without parentheses
24. Condition: If
package main
import (
"fmt"
)
func main() {
a := 10
if a > 1 {
fmt.Println("if true")
}
if b := 123 * 456; b < 10000 {
fmt.Println("another one, but with short
statement")
}
}
short statement, b is lives only inside if block
25. Condition: Switch
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)
}
}
Just like if, can have
short statement
Switch cases evaluate cases from top to bottom, stopping when a
case succeeds.
26. Switch Without Condition
func main() {
t := time.Now()
switch {
case t.Hour() < 12:
fmt.Println("Good morning!")
case t.Hour() < 17:
fmt.Println("Good afternoon.")
default:
fmt.Println("Good evening.")
}
}
Like writing long if/else chains
no condition
27. Structs
package main
import "fmt"
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
v.X = 4
fmt.Println(v.X)
}
A struct is a collection of fields.
Struct fields are accessed using a dot.
28. Structs
package main
import "fmt"
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
v.X = 4
p := &v
fmt.Println(v.X, p.X)
}
p is a pointer to v,
which has type *Vertex
Use dot to access
field of a pointer
29. The new Function
package main
import "fmt"
type Vertex struct {
X, Y int
}
func main() {
v := new(Vertex)
fmt.Println(v)
v.X, v.Y = 11, 9
fmt.Println(v)
}
The expression new(T) allocates a zeroed T value and returns a
pointer to it.
v has type: *Vertex
30. Slices
func main() {
p := []int{2, 3, 5, 7, 11, 13}
fmt.Println("p ==", p)
fmt.Println("p[1:4] ==", p[1:4]) // [3 5 7]
fmt.Println("p[:3] ==", p[:3]) // [2 3 5]
fmt.Println("p[4:] ==", p[4:]) // [11 13]
for i := 0; i < len(p); i++ {
fmt.Printf("p[%d] == %dn", i, p[i])
}
var z []int
if z == nil {
fmt.Println("nil value")
}
}
A slice points to an array of values and also includes a length.
The zero value of a slice is nil
empty slice: nil
31. Making Slices
func main() {
a := make([]int, 5)
printSlice("a", a)
b := make([]int, 0, 5)
printSlice("b", b)
}
func printSlice(s string, x []int) {
fmt.Printf("%s len=%d cap=%d %vn",
s, len(x), cap(x), x)
}
Use the make function to create slices.
make(type, length, capacity)
a len=5 cap=5 [0 0 0 0 0]
b len=0 cap=5 []
32. Array V.S. Slices
func main() {
var array = [...]string{"a", "b", "c"}
var slice = []string{"a", "b", "c"}
fmt.Printf("%Tn", array)
fmt.Printf("%Tn", slice)
//array = append(array, array...) // Won't
compile!
slice = append(slice, slice...)
fmt.Println(slice)
}
[3]string
[]string
[a b c a b c]
33. Maps
import "fmt"
type Vertex struct {
Lat, Long float64
}
var m map[string]Vertex
func main() {
m = make(map[string]Vertex)
m["Bell Labs"] = Vertex{
40.68433, -74.39967,
}
fmt.Println(m["Bell Labs"])
}
● A map maps keys to values.
● Maps must be created with make (not new) before use; the nil
map is empty and cannot be assigned to.
34. Maps Literals
var m = map[string]Vertex{
"Bell Labs": Vertex{
40.68433, -74.39967,
},
"Google": Vertex{
37.42202, -122.08408,
},
}
var m2 = map[string]Vertex{
"Bell Labs": {40.68433, -74.39967},
"Google": {37.42202, -122.08408}
}
map[key_type]value_type{
key1: value1, key2: value2 …
}
Can omit type name
35. Mutating Maps
m := make(map[string]int)
m["Answer"] = 42
Assigning
m, ok := m["Answer"]
if ok {
fmt.Println("key exists!")
}
Testing if a key exists
delete(m, "Answer")
Deleting an element
36. Iterating through Slices or Maps
package main
import "fmt"
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
var m = map[string]int{"a": 1, "b": 2}
func main() {
for i, v := range pow {
fmt.Printf("2**%d = %dn", i, v)
}
for k, v := range m {
fmt.Printf("%s: %dn", k, v)
}
}
Use the range keyword
37. The _ Variable
package main
import "fmt"
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
var m = map[string]int{"a": 1, "b": 2}
func main() {
for _, v := range pow {
fmt.Printf("%dn", v)
}
for _, v := range m {
fmt.Printf("%dn", v)
}
}
Go won’t let you compile you declare some variable but didn’t use it.
In this case, you can assign it to _ to indicate that it will not be used.
We don’t use index
here, assign it to _.
We don’t use key here,
assign it to _.
38. Go: Objects without Class
● No class, use interfaces instead
● No inheritance, use embedding instead
39. Method Declaration
type Vertex struct {
X, Y float64
}
func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
v := &Vertex{3, 4}
fmt.Println(v.Abs())
}
Basically look like functions, but with extra receiver declaration
before function name.
40. Method Declaration (cont’d)
func (t time.Time) bla() string {
return t.LocalTime().String()[0:5]
}
You may be tempted to declare new method on existing type, like
monkey patching in Python or Ruby.
cannot define new methods on non-local type time.
Time
type MyTime time.Time
func (t MyTime) bla() string {
return t.LocalTime().String()[0:5]
}
The correct way is to create a type synonym then define method on
it.
41. Interfaces
type Abser interface {
Abs() float64
}
type MyFloat float64
func (f MyFloat) Abs() float64 {
if f < 0 {
return float64(-f)
}
return float64(f)
}
● An interface type is defined by a set of methods.
● A value of interface type can hold any value that implements
those methods.
● Interfaces are satisfied implicitly
○ capture idioms and patterns after the code is being written
42. type Vertex struct {
X, Y float64
}
func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
var a Abser
f := MyFloat(-math.Sqrt2)
v := Vertex{3, 4}
a = f // a MyFloat implements Abser
a = &v // a *Vertex implements Abser
a = v // a Vertex, does NOT implement Abser
fmt.Println(a.Abs())
}
Interfaces (cont’d)
43. Interfaces (cont’d)
● Interfaces are infact like static-checked duck typing!
● When I see a bird that walks like a duck and swims like a duck
and quacks like a duck, I call that bird a duck.
44. package main
import "fmt"
type World struct{}
func (w *World) String() string {
return "世界"
}
func main() {
fmt.Printf("Hello, %sn", new(World))
}
Interfaces: Another Example
% go run hello.go
Hello, 世界
45. package fmt
// Stringer is implemented by any value that has a
String method,
// which defines the ``native'' format for that
value.
// The String method is used to print values passed
as an operand
// to any format that accepts a string or to an
unformatted printer
// such as Print.
type Stringer interface{
String() string
}
Interfaces: Another Example (cont’d)
fmt.Stringer
Naming Convention: An interface with single method
should be name as method name with “er” as postfix
46. Errors
type MyError struct {
When time.Time
What string
}
func (e *MyError) Error() string {
return fmt.Sprintf("at %v, %s",
e.When, e.What)
}
type error interface {
Error() string
}
Errors in go are defined as interface:
Defining new error type
47. Embedding
type Car struct {
wheelCount int
}
func (car Car) numberOfWheels() int {
return car.wheelCount
}
type Ferrari struct {
Car //anonymous field Car
}
func main() {
f := Ferrari{Car{4}}
fmt.Println("A Ferrari has this many wheels: ",
f.numberOfWheels())
}
Sort of “Inheritance” in OOP.
48. Goroutines
func say(s string) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
go say("world")
say("hello")
}
A goroutine is a lightweight thread managed by the Go runtime.
49. Channels
ch := make(chan int)
ch <- v // Send v to channel ch.
v := <-ch // Receive from ch, and
// assign value to v.
● Channels are a typed conduit through which you can send and
receive values.
● By default, sends and receives block until the other side is
ready.
● Channels can be buffered. Provide the buffer length as the
second argument to make to initialize a buffered channel:
● Sends to a buffered channel block only when the buffer is full.
Receives block when the buffer is empty.
ch := make(chan int, 100)
50. Channels (cont’)
func sum(a []int, c chan int) {
sum := 0
for _, v := range a {
sum += v
}
c <- sum // send sum to c
}
func main() {
a := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(a[:len(a)/2], c)
go sum(a[len(a)/2:], c)
x, y := <-c, <-c // receive from c
fmt.Println(x, y, x+y)
}
51. Closing a Channel
close(ch) // close the channel
v, ok := <-ch
if !ok {
fmt.Println("channel closed")
}
● A sender can close a channel to indicate that no more values
will be sent.
● Receivers can test whether a channel has been closed by
assigning a second parameter to the receive expression
52. Select
func fibonacci(c, quit chan int) {
x, y := 0, 1
for {
select {
case c <- x:
x, y = y, x+y
case <-quit:
fmt.Println("quit")
return
}
}
}
The select statement lets a goroutine wait on multiple communication
operations.
53. Defer, Panic, and Recover
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered in f", r)
}
}()
ofs, err := os.Create("/dev/stdout")
if err == nil {
fmt.Fprintf(ofs, "Hello, 世界n")
} else {
panic(err)
}
defer ofs.Close()
}
A defer statement pushes a function call onto a list. The list of
saved calls is executed after the surrounding function returns.
54. Generics?
Why does Go not have generic types?
Generics may well be added at some point. We don't feel an urgency
for them, although we understand some programmers do.
Generics are convenient but they come at a cost in complexity in the
type system and run-time. We haven't yet found a design that gives
value proportionate to the complexity, although we continue to think
about it. Meanwhile, Go's built-in maps and slices, plus the ability to
use the empty interface to construct containers (with explicit
unboxing) mean in many cases it is possible to write code that does
what generics would enable, if less smoothly.
From Go website:
55. Type Switch
func anything(data interface{})
{
switch data.(type) {
case int:
fmt.Println( "int")
case string:
fmt.Println( "string")
case fmt.Stringer:
fmt.Println( "Stringer")
default:
fmt.Println( "whatever...")
}
}
type World struct{}
func (w *World) String() string {
return "世界"
}
func main() {
anything("a string")
anything(42)
anything(new(World))
anything(make([]int, 5))
}
string
int
Stringer
whatever...
56. Type Assertion
func anything(data interface{}) {
s, ok := data.(fmt.Stringer)
if ok {
fmt.Printf( "We got Stringer:
%Tn", s)
} else {
fmt.Println( "bah!")
}
}
type World struct{}
func (w *World) String() string
{
return "世界"
}
func main() {
anything("a string")
anything(42)
anything(new(World))
anything(make([]int, 5))
}
bah!
bah!
We got Stringer: *main.World
bah!
57. Conclusion
● Go is a fast, small, easy-to-learn language
● Actively developed by Google
● Tons of third-party libraries
● Learn it by using it!
58. References
● Go Official Tutorial [website]
● Effective Go [website]
● Advanced Go Concurrency Patterns [Slide, Video]
● Go and Rust — objects without class [lwn.net]