Date post: | 08-Sep-2014 |
Category: |
Technology |
Upload: | yo-an-lin |
View: | 3,533 times |
Download: | 0 times |
Happy Go Part IIYo-An Lin (c9s) [email protected] [email protected]
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)
Benchmarkhttp://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
• Sound Cloud
• BCC
• Canonical
• Heroku
• Carbon Games
• Iron.io
• SmugMug
• Bitly
• CloudFlare
Enough Open Sourced Packages?
15,298 packageshttp://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-for-google-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 分開
$GOPATHmkdir ~/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, world\n") }
Hello World
$ go run hello.go
$ go build -o hello hello.go $ ./hello
Go commands
• go run 編譯後執⾏行程式 (必須是 main package)
• 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.gogo run -x app.go
• go install
Types
Types
• int, int8, int16, int32, int64,
• float32, float64
• string
• byte
Basic Type Conversion
var a int32 = 32var 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 bytea 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: %#v\n", str[0]) fmt.Printf("str[2:5] = []byte: %#v\n", str[2:5])
str[0] = byte: 0x61str[2:5] = []byte: "cde"
Slice - string
var str = "abcdefg" for i, c := range str { fmt.Printf("str[%d] = %c\n", i, c) }
str[0] = astr[1] = bstr[2] = cstr[3] = dstr[4] = estr[5] = fstr[6] = g
More about stringhttp://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 headerfunc addOne(list []int) { for i, _ := range list { // this modify the actual data // through the data pointer. list[i]++ }}
Slice - internalsx := [3]string{"Лайка", "Белка", "Стрелка"}s := x[:] // a slice referencing the storage of x
Slice - internalsx := [3]string{"Лайка", "Белка", "Стрелка"}s := x[:] // a slice referencing the storage of x
Slice - internalsx := [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 Slicehttp://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)
0x2101ef0180
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”
Structtype Contact struct { Name string Phone string}
Structtype Contact struct { Name string Phone string}
The type name
Structtype Contact struct { Name string Phone string}
The type of “Contact “ is a struct
Structtype Contact struct { Name string Phone string}
Struct Field Name
Structtype 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"}
p1 := Contact{"Lisa", "1234"}
…Equals To…
Struct Allocation
The expressions new(File) and &File{} are equivalent.
new(File)&File{}
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)
contact2 := &Contact{"Mary", "12345678"}fmt.Println(contact1.Name)
Allocate a struct and return the reference
Accessing Struct Fields
contact1 := Contact{"Mary", "12345678"}fmt.Println(contact1.Name)
contact2 := &Contact{"Mary", "12345678"}fmt.Println(contact1.Name)
Pointer of type Contact
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 inttype ScoreMap map[string]inttype NickName string
Custom Types
type Score inttype ScoreMap map[string]inttype NickName string
type Score is a int type
Custom Typestype Score int!func CalculateScore(a Score, b Score) Score { return a + b} Strict type of your data makes your
application safer.
Custom Typestype 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 Typestype Score int!func CalculateScore(a Score, b Score) Score { return a + b} Strict type of your data makes your
application safer.
CalculateScore( 20 )CalculateScore( Score(20) )
Compilation FailCompilation 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 := &ab.Say()
Type Methods
a := NickName("foo")a.Say()
b := &ab.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()}
interfacetype Worker interface { Work()}
type SeedWorker struct{}!func (self *SeedWorker) Work() { // work...}
interface// accept anything implements // the interface of Workerfunc 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{}
type Foo struct{}type Bar struct{}
Given Struct Foo and Bar
interface{}
type Foo struct{}type Bar struct{}
Given Struct Foo and Bar
var a interface{} = Foo{} var b interface{} = &Foo{} var c interface{} = &Bar{} b = c a = b
interface{}
type anything interface{}
var a anything = Foo{}var b anything = &Foo{}var c anything = &Bar{}
interface{}
func AcceptAnything(a anything) { // do something}func main() { AcceptAnything(Foo{}) AcceptAnything(&Foo{}) AcceptAnything(&Bar{})}
type anything interface{}
Building Web Applications
Using net/http
Data Structure For Page
$ mkdir wiki$ cd wiki$ vim page.go
Data Structure For Pagepackage main!import ( "fmt" "io/ioutil")
Data Structure For Pagetype Page struct { Title string Body []byte}
Data Structure For Pagetype 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 Pagefunc 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$ ./wikiThis is a sample page.
Introducing net/httppackage main!import ( "fmt" "net/http")
Introducing net/http
func handler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])}
Type of Handler
Introducing net/http
func handler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])}
Resource handle which implements 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:])}
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/httppackage main!import ( "fmt" "io/ioutil" "net/http")
Import http package.
Using net/httpfunc 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/httpfunc 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/httpfunc 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 handlerfunc 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 handlerfunc 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