• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Happy Go Programming
 

Happy Go Programming

on

  • 3,304 views

golang, go, programming, web applications.

golang, go, programming, web applications.

Statistics

Views

Total Views
3,304
Views on SlideShare
3,239
Embed Views
65

Actions

Likes
18
Downloads
80
Comments
0

4 Embeds 65

http://www.plurk.com 43
https://twitter.com 15
https://www.facebook.com 4
https://www.plurk.com 3

Accessibility

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Happy Go Programming Happy Go Programming Presentation Transcript

    • 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