Happy Go Part II
Yo-An Lin (c9s)
c9s@twitter.com
c9s@github.com
Intro
•

was the GitHub Top 1
Contributor ( http://git.io/top )

•

3+ years Perl/VimL
programming

•

3+ years PHP programming

•

2+ years Go programming
Go?
Ken Thompson
Rob Pike
Started since 2007
Announced in
November 2009
Used in some of Google’s
production system
What’s Go
•

Statically-Typed Language 靜態型別編譯語⾔言

•

Built-in Concurrency 內建並發性⽀支持

•

Statically-linked Native Binary 靜態連結原⽣生⼆二進位執⾏行檔

•

Fast compilation times 極快速的編譯

•

Remote package management 內建外部套件管理

•

Garbage Collection 使⽤用垃圾收集器

•

Safety 安全 (race conditions, type and memory safety for
multithreaded program)
About The Language
•

Concise variable declaration 簡潔的變數定義

•

Type Inference 型別推導

•

Easy to use 簡易使⽤用

•

Composition instead of Inheritance.

•

Use Interface 使⽤用介⾯面取代 is-a 繼承

•

multiple return value 多回傳值函數
About The Tools
•

語⾔言規格的修改,可透過 go fix 來將舊版語法或程式碼做⾃自
動修正

•

編碼⾵風格可透過 go fmt 來統⼀一所有格式,以及⾃自動去除空
⽩白⾏行、換⾏行、縮排等等。 且可以⽤用 grammar 的⽅方式來描述
語法。

•

內建 profiling tools 且⽀支持 Goole pprof ,可直接在 http
server 上開 profiler API,利⽤用命令列⼯工具遠端取得 CPU,
Memory 使⽤用狀況並進⾏行分析,或產⽣生 call graph 等等資
料。

•

遠端套件可直接透過 go get 安裝
What’s the difference?
那麼有什麼不同呢?
Interpreted language
Statically compiled
language
Statically-typed (or
compiled) languages are
usually faster
Benchmark
•

Faster than Node.js, Python, Perl, PHP, Ruby
(without C/C++ extensions)

•

A bit slower than C, C++ and Java (sometimes
faster than Java)

•

Low memory footprint (10+ times lower than Java)
Benchmark
http://www.techempower.com/benchmarks/
and it compiles fast
But it costs a lot of time
But it costs a lot of time
Go solves this
problem
Concurrency?
Prefork
Prefork
Prefork
Prefork
•

Hard to share data between processes.

•

Costs a lot of CPU cycle.

•

Copying process is time consuming.

•

Waste a lot of memory.
Just use Go Routine
Just use Go Routine

All in one process
Just use Go Routine
•

Threaded worker pool

•

use pipeline (channel) to communicate

•

CSP (Communicating Sequential Processes)

http://golang.org/doc/faq
Easier Deployment
Deployment Pain
•

Install required packages

•

Install application package dependencies

•

(dependency hell)

•

(incompatible version hell)

•

(10 hours later…)

•

ok, finally onlined.
You can just build &
scp
And it works
Q & A Time
————————
Ready For
Production?
Companies using Go
•

Google

•

Carbon Games

•

Sound Cloud

•

Iron.io

•

BCC

•

SmugMug

•

Canonical

•

Bitly

•

Heroku

•

CloudFlare
Enough Open
Sourced Packages?
15,298 packages
http://godoc.org/-/index
Is it popular?
Supported OS?
Supported OS
•

Linux

•

BSD, OpenBSD

•

Windows

•

Mac OS

•

Plan 9
Architectures?
Architectures
•

i386

•

amd64

•

arm
Development
Environment
For Go
Go IDE
•

Sublime Text 2

•

IntelliJ

•

LiteIDE

•

Intype

•

NetBeans

•

Eclipse

•

Zeus

http://geekmonkey.org/articles/20-comparison-of-ides-forgoogle-go
go/misc
•

misc/vim : generic vim plugin

•

misc/emacs : emacs go mode

•

misc/git : pre-commit hook (run go fmt before commmit)

•

misc/bash : bash completion

•

zsh/go : zsh completion

•

misc/cgo : cgo examples
vim: gocode

•

go completion daemon

•

vim omni completion support

•

scan code from $GOPATH
Go Environment
•

$GOROOT ( defaults to /usr/local/go )

•

$GOPATH ( your packages )

•

$GOARCH

•

$GOOS
$GOPATH
mkdir ~/go
export GOPATH=~/go

執⾏行 go get 時,packages 會安裝到
GOPATH 第⼀一個 path 內
$GOPATH
mkdir ~/go/vendor
mkdir ~/go/private
export GOPATH=~/go/vendor:~/go/private

可利⽤用 $GOPATH 將私⽤用 package 分開
$GOPATH
mkdir ~/go
export GOPATH=~/go

path

description

~/go/src

your source code

~/go/pkg

compiled packages (*.a)

~/go/bin

command-line binary
Hello World
$ vim hello.go
package main
!

import "fmt"
!

func main() {
fmt.Printf("hello, worldn")
}
Hello World
$ go run hello.go

$ go build -o hello hello.go
$ ./hello
Go commands
編譯後執⾏行程式 (必須是 main package)

•

go run

•

go build 編譯

•

go install 編譯並且安裝

•

go get 抓取遠端套件並且編譯安裝
Basic Application
Basic Application
package main	
!

import "fmt"	
!

func main() {	
	 fmt.Println("anything here")	
}
Basic commands
•

go build app.go

go build -x app.go

•

go run app.go

go run -x app.go

•

go install
Types
Types
•

int, int8, int16, int32, int64,

•

float32, float64

•

string

•

byte
Basic Type Conversion
	 var a int32 = 32	
	 var b int64 = int64(a)	
	 var c int = int(a)
Basic Type Conversion
	 var str = "Hello World"	
	 var data []byte = []byte(str)	
	 fmt.Println(data)
Basic Type Conversion
	 var str = "Hello World"	
	 var data []byte = []byte(str)	
	 fmt.Println(data)

[72 101 108 108 111 32 87 111 114 108 100]
Slice & Array
Slice & Array Type

•

Array: [10]int, [3]int

•

Slice: []int, []string, []byte
Slice & Array
Array:


•




list := […]int{1,2,3,4,5 }

list := [5]int{ 1,2,3,4,5 }
Slice:


•




list := []int{ 1, 2, 3 }

list := []string{ “foo”, “bar”, “zoo” }
Slice & Array
Array:


•




var list = […]int{1,2,3,4,5 }

var list = [5]int{ 1,2,3,4,5 }
Slice:


•




var list = []int{ 1, 2, 3 }

var list = []string{ “foo”, “bar”, “zoo” }
Slice & Array
Array:


•




var list [5]int = […]int{1,2,3,4,5 }

var list [5]int = [5]int{ 1,2,3,4,5 }
Slice:


•




var list []int = []int{ 1, 2, 3 }

var list []string = []string{ “foo”, “bar”, “zoo” }
Slice 切⽚片
Slice - appending
	 names := []string{"Mary", "Lily", "July"}	
	 names = append(names, "Jane")
Slice - iterating
	 names := []string{“Mary","Lily","July"}	
!

	 for i, name := range names {	
	 	 fmt.Println(i, name)	
	 }
String = Slice of byte
a string is in effect a read-only slice of bytes
Slice - string
•

string is basically a slice of byte.

•

slice is immutable, string is also immutable.

•

which means: “no delete or insert in specific
position”

•

but you can create a new slice references to
another slice with position and length.
Slice - string
	 var str = "abcdefg"	
	 fmt.Printf("str[0] = byte: %#vn", str[0])	
	 fmt.Printf("str[2:5] = []byte: %#vn", str[2:5])

str[0] = byte: 0x61	
str[2:5] = []byte: "cde"
Slice - string
	
	
	
	

var str = "abcdefg"	
for i, c := range str {	
	 fmt.Printf("str[%d] = %cn", i, c)	
}

str[0]
str[1]
str[2]
str[3]
str[4]
str[5]
str[6]

=
=
=
=
=
=
=

a	
b	
c	
d	
e	
f	
g
More about string
http://blog.golang.org/strings
Slice - internals
Slice internals: slice header

[]byte{ 60, 61, 62, 63, 64 }
Slice internal: slice header
	
	
	
	
	

// this creates a slice with header:	
//
start from 0	
//
length = 7	
//
data = pointer to the int array.	
foo := []int{0, 1, 2, 3, 4, 5, 6}	

!

	 // this copy the slice header to the function	
	 addOne(foo)
Slice internal: slice header
// we get a copy of slice header	
func addOne(list []int) {	
	 for i, _ := range list {	
	 	 // this modify the actual data 	
// through the data pointer.	
	
list[i]++	
	 }	
}
Slice - internals
x := [3]string{"Лайка", "Белка", "Стрелка"}	
s := x[:] // a slice referencing the storage of x
Slice - internals
x := [3]string{"Лайка", "Белка", "Стрелка"}	
s := x[:] // a slice referencing the storage of x
Slice - internals
x := [3]string{"Лайка", "Белка", "Стрелка"}	
s := x[:] // a slice referencing the storage of x
Slice - internals
s = s[2:4]
Slice - internals
s = s[2:4]
Slice - internals
s = s[2:4]

Slicing does not copy the slice's data. It creates a new
slice header that points to the original array.
Slice - internals
s = s[:cap(s)]
Slice - internals
s = s[:cap(s)]
More About Slice
http://blog.golang.org/slices
http://blog.golang.org/go-slices-usage-and-internals
Map
Map
contacts := map[string]string {}
Type of Key
Map
contacts := map[string]string {}
Type of Value
Map
contacts := map[string]string {}
contacts := map[string]string {	
	 "Jack": "02-2345678",	
}
Map
contacts := map[string]string {}
contacts := map[string]string {	
	 "Jack": "02-2345678",	
}	
Initialised Key

Initialised Value
Map
contacts := map[string]string {}
contacts := map[string]string {	
	 "Jack": "02-2345678",	
}	
“,” Composite Literal Syntax
Map
contacts := map[string]string {}
contacts := map[string]string {	
	 "Jack": “02-2345678",	
	 "Lisa": "1234567890",	
}	
“,” Composite Literal Syntax
Map
var contacts map[string]string 	
= map[string]string {	
	 “Jack”: "02-2345678",	
}
Map - assign
	 contacts := map[string]string{}	
!

	 contacts["key"] = "value"
Map - defined
	 contacts := map[string]string{}	
!

	 if _, ok := contacts["key"]; ok {	
!

	 }	

Multiple Return Value
Map - defined
	 contacts := map[string]string{}	
!

	 if _, ok := contacts["key"]; ok {	
!

	 }	

Variable Assignment
Map - defined
	 contacts := map[string]string{}	
!

	 if _, ok := contacts["key"]; ok {	
!

	 }	

boolean context
Map - defined
	 contacts := map[string]string{}	
!

	 if _, ok := contacts["key"]; ok {	
!

	 }	

boolean: if found
Map - defined
	 contacts := map[string]string{}	
!

	 if _, ok := contacts["key"]; ok {	
!

	 }	

actual value with the defined type
Map - defined
	 if val, ok := contacts["key"]; ok {	
	 	 _ = val	
	 }	
Unused Variable
Map - delete

Built-in Function

	 contacts := map[string]string{}	
	 contacts["key"] = "value"	
	 delete(contacts, “key")
Map - iterating
	 contacts["key"] = "value"	
	 contacts["key2"] = “value2"	
!

	
	
	
	

for key, val := range contacts {	
	 _ = key	
	 _ = val	
}
Pointer & Reference
Pointer
•

pointer is basically like we used in C.

•

easy to use but safer than C.

•

no segmentation-fault.!

•

compile-time type checking.
Pointer: new & make

•

new() - doesn’t initialise value. zero-ed memory
allocation.!

•

make() - allocation with data initialisation.
Pointer
	 a := new(int)	
	 fmt.Println(a)	
	 fmt.Println(*a)
Pointer
	 a := new(int)	
	 fmt.Println(a)	
	 fmt.Println(*a)

0x2101ef018	
0
Reference
	
	
	
	

var a int = 10	
var b *int = &a	
a = 12	
fmt.Println(a, *b)	

12 12
Struct
Struct

•

similar to the struct we used in C.

•

but you can embed another struct in your struct. so
called “embedded struct”
Struct
type Contact struct {	
	 Name string	
	 Phone string	
}
Struct
type Contact struct {	
	 Name string	
	 Phone string	
}	
The type name
Struct
type Contact struct {	
	 Name string	
	 Phone string	
}	
The type of “Contact “ is a struct
Struct
type Contact struct {	
	 Name string	
	 Phone string	
}	
Struct Field Name
Struct
type Contact struct {	
	 Name string	
	 Phone string	
}	
Field Type
Struct Allocation
func main() {	
	 p1 := Contact{Name: "Lisa", Phone: "1234"}	
	 p2 := Contact{"Mary", "2345"}	
	 fmt.Println(p1, p2)	
}
Composite Literal

a := [...]string
{Enone: "no error", Eio: "Eio", Einval: "invalid argument"}	
s := []string
{Enone: "no error", Eio: "Eio", Einval: "invalid argument"}	
m := map[int]string{Enone: "no error", Eio: "Eio", Einval: "invalid argument"}
Struct Allocation
	 p1 := Contact{Name: "Lisa", Phone: "1234"}

…Equals To…
	 p1 := Contact{"Lisa", "1234"}
Struct Allocation
new(File)	
&File{}

The expressions new(File) and &File{} are equivalent.
Accessing Struct Fields
contact1 := Contact{"Mary", "12345678"}	
fmt.Println(contact1.Name)
Use “.” to access struct field
Accessing Struct Fields
contact1 := Contact{"Mary", "12345678"}	
fmt.Println(contact1.Name)
Allocate a struct and return the reference

contact2 := &Contact{"Mary", "12345678"}	
fmt.Println(contact1.Name)
Accessing Struct Fields
contact1 := Contact{"Mary", "12345678"}	
fmt.Println(contact1.Name)
Pointer of type Contact

contact2 := &Contact{"Mary", "12345678"}	
fmt.Println(contact1.Name)
Accessing Struct Fields
contact1 := Contact{"Mary", "12345678"}	
fmt.Println(contact1.Name)

contact2 := &Contact{"Mary", "12345678"}	
fmt.Println(contact2.Name)
Always use “.” to access struct field
Custom Type
Custom Types
type Score int	
type ScoreMap map[string]int	
type NickName string
Custom Types
type Score int	
type ScoreMap map[string]int	
type NickName string

type Score is a int type
Custom Types
type Score int	
!

func CalculateScore(a Score, b Score) Score {	
	 return a + b	
}
Strict type of your data makes your
application safer.
Custom Types
type Score int	
!

func CalculateScore(a Score, b Score) Score {	
	 return a + b	
}
Strict type of your data makes your
application safer.

CalculateScore( 20 )

Compilation Fail
Custom Types
type Score int	
!

func CalculateScore(a Score, b Score) Score {	
	 return a + b	
}
Strict type of your data makes your
application safer.

CalculateScore( 20 )

Compilation Fail

CalculateScore( Score(20) ) Compilation Pass
Type Methods
type NickName string	
!

func (self NickName) Say() {	
	 fmt.Println(self)	
}
Type Methods
type NickName string	
!

func (self NickName) Say() {	
	 fmt.Println(self)	
}	
Receiver
Type Methods
type NickName string	
!

func (self * NickName) Say() {	
	 fmt.Println(self)	
}	
You may also use the reference. (faster)
Type Methods
a := NickName("foo")	
a.Say()
Allocate a string
Type Methods
a := NickName("foo")	
a.Say()
Type cast to NickName
Type Methods
a := NickName("foo")	
a.Say()
b := &a	
b.Say()
Type Methods
a := NickName("foo")	
a.Say()
b := &a	
b.Say()
Always use “.” to access fields or methods .
Interface
Interface
•

interface defines the requirement of the object
method prototype.

•

you define the requirement and check the
requirement in both compile-time and runtime.
interface
type Worker interface {	
	 Work()	
}
interface
type Worker interface {	
	 Work()	
}	
type SeedWorker struct{}	
!

func (self *SeedWorker) Work() {	
	 // work...	
}
interface
// accept anything implements 	
// the interface of Worker	
func HandleData(worker Worker) {	
	 worker.Work()	
}	
!

func main() {	
	 HandleData(SeedWorker{})	
	 HandleData(&SeedWorker{})	
}
interface{}
•

interface{} is basically a universal pointer.

•

just like “id” we used in Objective-C

•

just like the void pointer we used in C.

•

interface{} means an interface without requirement.
interface{}
Given Struct Foo and Bar
type Foo struct{}	
type Bar struct{}
interface{}
Given Struct Foo and Bar
type Foo struct{}	
type Bar struct{}
	
	
	
	
	

var
var
var
b =
a =

a interface{} = Foo{}	
b interface{} = &Foo{}	
c interface{} = &Bar{}	
c	
b
interface{}
type anything interface{}
var a anything = Foo{}	
var b anything = &Foo{}	
var c anything = &Bar{}
interface{}
type anything interface{}	
func AcceptAnything(a anything) {	
	 // do something	
}	
func main() {	
	 AcceptAnything(Foo{})	
	 AcceptAnything(&Foo{})	
	 AcceptAnything(&Bar{})	
}
Building Web
Applications
Using net/http
Data Structure For Page
$ mkdir wiki	
$ cd wiki	
$ vim page.go
Data Structure For Page
package main	
!

import (	
	 "fmt"	
	 "io/ioutil"	
)
Data Structure For Page
type Page struct {	
	 Title string	
	 Body []byte	
}
Data Structure For Page
type Page struct {	
	 Title string	
	 Body []byte	
}	

func (p *Page) save() error {	
	 filename := p.Title + ".txt"	
	 return ioutil.WriteFile(filename, p.Body, 0600)	
}
Data Structure For Page
func loadPage(title string) (*Page, error) {	
	 filename := title + ".txt"	
	 body, err := ioutil.ReadFile(filename)	
	 if err != nil {	
	 	 return nil, err	
	 }	
	 return &Page{Title: title, Body: body}, nil	
}
Build it!
$ go build wiki.go
Build it!
$ go build wiki.go	
$ ./wiki	
This is a sample page.
Introducing net/http
package main	
!

import (	
	 "fmt"	
	 "net/http"	
)
Introducing net/http
Type of Handler

func handler(w http.ResponseWriter, r *http.Request) {	
	 fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])	
}
Introducing net/http
Resource handle which implements Writer interface.

func handler(w http.ResponseWriter, r *http.Request) {	
	 fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])	
}
Introducing net/http
func handler(w http.ResponseWriter, r *http.Request) {	
	 fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])	
}	
Call w.Write… (this satisfies Writer interface)
Introducing net/http
func handler(w http.ResponseWriter, r *http.Request) {	
	 fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])	
}	
!
func main() {	
	 http.HandleFunc("/", handler)	
	 http.ListenAndServe(":8080", nil)	
}	
Calls the HandleFunc function in “http” package.
This function accepts a function pointer which satisfies the interface.
Introducing net/http
func handler(w http.ResponseWriter, r *http.Request) {	
	 fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])	
}	
!
func main() {	
	 http.HandleFunc("/", handler)	
	 http.ListenAndServe(":8080", nil)	
}	
Binds HTTP server to “:8080”
Introducing net/http
http://localhost:8080/monkeys

Hi there, I love monkeys!
Using net/http
package main	
!

import (	
	 "fmt"	
	 "io/ioutil"	
	 "net/http"	
)	
Import http package.
Using net/http
func viewHandler(w http.ResponseWriter, r *http.Request) {	
	 title := r.URL.Path[len("/view/"):]	
	 p, _ := loadPage(title)	
	 fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.Title, p.Body)	
}	
The URL of current request
Using net/http
func viewHandler(w http.ResponseWriter, r *http.Request) {	
	 title := r.URL.Path[len("/view/"):]	
	 p, _ := loadPage(title)	
	 fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.Title, p.Body)	
}	
Strip the first 6 bytes from URL Path
Using net/http
func viewHandler(w http.ResponseWriter, r *http.Request) {	
	 title := r.URL.Path[len("/view/"):]	
	 p, _ := loadPage(title)	
	 fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.Title, p.Body)	
}	
Load the page data from file.
Using net/http
func main() {	
	 http.HandleFunc("/view/", viewHandler)	
	 http.ListenAndServe(":8080", nil)	
}
Build it!
$ go build wiki.go
Build it!
$
$
$
$

vim test.txt	
go build wiki.go	
./wiki	
curl http://localhost:8080/view/test
Edit handler
func editHandler(w http.ResponseWriter, r *http.Request) {	
	 title := r.URL.Path[len("/edit/"):]	
	 p, err := loadPage(title)	
	 if err != nil {	
	 	 p = &Page{Title: title}	
	 }	
	 fmt.Fprintf(w, "<h1>Editing %s</h1>"+	
	 	 "<form action="/save/%s" method="POST">"+	
	 	 "<textarea name="body">%s</textarea><br>"+	
	 	 "<input type="submit" value="Save">"+	
	 	 "</form>",	
	 	 p.Title, p.Title, p.Body)	
}
The html/template package
package main	
!

import (	
	 "html/template"	
	 "io/ioutil"	
	 "net/http"	
)
The html/template package
func editHandler(w http.ResponseWriter, r *http.Request) {	
	 title := r.URL.Path[len("/edit/"):]	
	 p, err := loadPage(title)	
	 if err != nil {	
	 	 p = &Page{Title: title}	
	 }	
	 t, _ := template.ParseFiles("edit.html")	
	 t.Execute(w, p)	
}
The html/template package
<h1>Editing {{.Title}}</h1>	
!
<form action="/save/{{.Title}}" method="POST">	
<div><textarea name="body" rows="20"
cols="80">{{printf "%s" .Body}}</textarea></div>	
<div><input type="submit" value="Save"></div>	
</form>
Save handler
func saveHandler(w http.ResponseWriter, r *http.Request) {	
title := r.URL.Path[len("/save/"):]	
body := r.FormValue("body")	
p := &Page{Title: title, Body: []byte(body)}	
p.save()	
http.Redirect(w, r, "/view/"+title, http.StatusFound)	
}	
!
http.HandleFunc(“/save/“, saveHandler)	
!
http://localhost:8080/edit/test
# access test.txt

Happy Go Programming