Happy Go Programming

  • 3,651 views
Uploaded on

golang, go, programming, web applications.

golang, go, programming, web applications.

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
3,651
On Slideshare
0
From Embeds
0
Number of Embeds
4

Actions

Shares
Downloads
96
Comments
0
Likes
19

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Happy Go Part II Yo-An Lin (c9s) c9s@twitter.com c9s@github.com
  • 2. Intro • was the GitHub Top 1 Contributor ( http://git.io/top ) • 3+ years Perl/VimL programming • 3+ years PHP programming • 2+ years Go programming
  • 3. Go?
  • 4. Ken Thompson Rob Pike
  • 5. Started since 2007
  • 6. Announced in November 2009
  • 7. Used in some of Google’s production system
  • 8. 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)
  • 9. About The Language • Concise variable declaration 簡潔的變數定義 • Type Inference 型別推導 • Easy to use 簡易使⽤用 • Composition instead of Inheritance. • Use Interface 使⽤用介⾯面取代 is-a 繼承 • multiple return value 多回傳值函數
  • 10. About The Tools • 語⾔言規格的修改,可透過 go fix 來將舊版語法或程式碼做⾃自 動修正 • 編碼⾵風格可透過 go fmt 來統⼀一所有格式,以及⾃自動去除空 ⽩白⾏行、換⾏行、縮排等等。 且可以⽤用 grammar 的⽅方式來描述 語法。 • 內建 profiling tools 且⽀支持 Goole pprof ,可直接在 http server 上開 profiler API,利⽤用命令列⼯工具遠端取得 CPU, Memory 使⽤用狀況並進⾏行分析,或產⽣生 call graph 等等資 料。 • 遠端套件可直接透過 go get 安裝
  • 11. What’s the difference? 那麼有什麼不同呢?
  • 12. Interpreted language
  • 13. Statically compiled language
  • 14. Statically-typed (or compiled) languages are usually faster
  • 15. 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)
  • 16. Benchmark http://www.techempower.com/benchmarks/
  • 17. and it compiles fast
  • 18. But it costs a lot of time
  • 19. But it costs a lot of time
  • 20. Go solves this problem
  • 21. Concurrency?
  • 22. Prefork
  • 23. Prefork
  • 24. Prefork
  • 25. Prefork • Hard to share data between processes. • Costs a lot of CPU cycle. • Copying process is time consuming. • Waste a lot of memory.
  • 26. Just use Go Routine
  • 27. Just use Go Routine All in one process
  • 28. Just use Go Routine • Threaded worker pool • use pipeline (channel) to communicate • CSP (Communicating Sequential Processes) http://golang.org/doc/faq
  • 29. Easier Deployment
  • 30. Deployment Pain • Install required packages • Install application package dependencies • (dependency hell) • (incompatible version hell) • (10 hours later…) • ok, finally onlined.
  • 31. You can just build & scp
  • 32. And it works
  • 33. Q & A Time
  • 34. ————————
  • 35. Ready For Production?
  • 36. Companies using Go • Google • Carbon Games • Sound Cloud • Iron.io • BCC • SmugMug • Canonical • Bitly • Heroku • CloudFlare
  • 37. Enough Open Sourced Packages?
  • 38. 15,298 packages http://godoc.org/-/index
  • 39. Is it popular?
  • 40. Supported OS?
  • 41. Supported OS • Linux • BSD, OpenBSD • Windows • Mac OS • Plan 9
  • 42. Architectures?
  • 43. Architectures • i386 • amd64 • arm
  • 44. Development Environment For Go
  • 45. Go IDE • Sublime Text 2 • IntelliJ • LiteIDE • Intype • NetBeans • Eclipse • Zeus http://geekmonkey.org/articles/20-comparison-of-ides-forgoogle-go
  • 46. 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
  • 47. vim: gocode • go completion daemon • vim omni completion support • scan code from $GOPATH
  • 48. Go Environment • $GOROOT ( defaults to /usr/local/go ) • $GOPATH ( your packages ) • $GOARCH • $GOOS
  • 49. $GOPATH mkdir ~/go export GOPATH=~/go 執⾏行 go get 時,packages 會安裝到 GOPATH 第⼀一個 path 內
  • 50. $GOPATH mkdir ~/go/vendor mkdir ~/go/private export GOPATH=~/go/vendor:~/go/private 可利⽤用 $GOPATH 將私⽤用 package 分開
  • 51. $GOPATH mkdir ~/go export GOPATH=~/go path description ~/go/src your source code ~/go/pkg compiled packages (*.a) ~/go/bin command-line binary
  • 52. Hello World $ vim hello.go package main ! import "fmt" ! func main() { fmt.Printf("hello, worldn") }
  • 53. Hello World $ go run hello.go $ go build -o hello hello.go $ ./hello
  • 54. Go commands 編譯後執⾏行程式 (必須是 main package) • go run • go build 編譯 • go install 編譯並且安裝 • go get 抓取遠端套件並且編譯安裝
  • 55. Basic Application
  • 56. Basic Application package main ! import "fmt" ! func main() { fmt.Println("anything here") }
  • 57. Basic commands • go build app.go
 go build -x app.go • go run app.go
 go run -x app.go • go install
  • 58. Types
  • 59. Types • int, int8, int16, int32, int64, • float32, float64 • string • byte
  • 60. Basic Type Conversion var a int32 = 32 var b int64 = int64(a) var c int = int(a)
  • 61. Basic Type Conversion var str = "Hello World" var data []byte = []byte(str) fmt.Println(data)
  • 62. 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]
  • 63. Slice & Array
  • 64. Slice & Array Type • Array: [10]int, [3]int • Slice: []int, []string, []byte
  • 65. 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” }
  • 66. 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” }
  • 67. 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” }
  • 68. Slice 切⽚片
  • 69. Slice - appending names := []string{"Mary", "Lily", "July"} names = append(names, "Jane")
  • 70. Slice - iterating names := []string{“Mary","Lily","July"} ! for i, name := range names { fmt.Println(i, name) }
  • 71. String = Slice of byte a string is in effect a read-only slice of bytes
  • 72. 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.
  • 73. 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"
  • 74. 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
  • 75. More about string http://blog.golang.org/strings
  • 76. Slice - internals
  • 77. Slice internals: slice header []byte{ 60, 61, 62, 63, 64 }
  • 78. 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)
  • 79. 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]++ } }
  • 80. Slice - internals x := [3]string{"Лайка", "Белка", "Стрелка"} s := x[:] // a slice referencing the storage of x
  • 81. Slice - internals x := [3]string{"Лайка", "Белка", "Стрелка"} s := x[:] // a slice referencing the storage of x
  • 82. Slice - internals x := [3]string{"Лайка", "Белка", "Стрелка"} s := x[:] // a slice referencing the storage of x
  • 83. Slice - internals s = s[2:4]
  • 84. Slice - internals s = s[2:4]
  • 85. 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.
  • 86. Slice - internals s = s[:cap(s)]
  • 87. Slice - internals s = s[:cap(s)]
  • 88. More About Slice http://blog.golang.org/slices http://blog.golang.org/go-slices-usage-and-internals
  • 89. Map
  • 90. Map contacts := map[string]string {} Type of Key
  • 91. Map contacts := map[string]string {} Type of Value
  • 92. Map contacts := map[string]string {} contacts := map[string]string { "Jack": "02-2345678", }
  • 93. Map contacts := map[string]string {} contacts := map[string]string { "Jack": "02-2345678", } Initialised Key Initialised Value
  • 94. Map contacts := map[string]string {} contacts := map[string]string { "Jack": "02-2345678", } “,” Composite Literal Syntax
  • 95. Map contacts := map[string]string {} contacts := map[string]string { "Jack": “02-2345678", "Lisa": "1234567890", } “,” Composite Literal Syntax
  • 96. Map var contacts map[string]string = map[string]string { “Jack”: "02-2345678", }
  • 97. Map - assign contacts := map[string]string{} ! contacts["key"] = "value"
  • 98. Map - defined contacts := map[string]string{} ! if _, ok := contacts["key"]; ok { ! } Multiple Return Value
  • 99. Map - defined contacts := map[string]string{} ! if _, ok := contacts["key"]; ok { ! } Variable Assignment
  • 100. Map - defined contacts := map[string]string{} ! if _, ok := contacts["key"]; ok { ! } boolean context
  • 101. Map - defined contacts := map[string]string{} ! if _, ok := contacts["key"]; ok { ! } boolean: if found
  • 102. Map - defined contacts := map[string]string{} ! if _, ok := contacts["key"]; ok { ! } actual value with the defined type
  • 103. Map - defined if val, ok := contacts["key"]; ok { _ = val } Unused Variable
  • 104. Map - delete Built-in Function contacts := map[string]string{} contacts["key"] = "value" delete(contacts, “key")
  • 105. Map - iterating contacts["key"] = "value" contacts["key2"] = “value2" ! for key, val := range contacts { _ = key _ = val }
  • 106. Pointer & Reference
  • 107. Pointer • pointer is basically like we used in C. • easy to use but safer than C. • no segmentation-fault.! • compile-time type checking.
  • 108. Pointer: new & make • new() - doesn’t initialise value. zero-ed memory allocation.! • make() - allocation with data initialisation.
  • 109. Pointer a := new(int) fmt.Println(a) fmt.Println(*a)
  • 110. Pointer a := new(int) fmt.Println(a) fmt.Println(*a) 0x2101ef018 0
  • 111. Reference var a int = 10 var b *int = &a a = 12 fmt.Println(a, *b) 12 12
  • 112. Struct
  • 113. Struct • similar to the struct we used in C. • but you can embed another struct in your struct. so called “embedded struct”
  • 114. Struct type Contact struct { Name string Phone string }
  • 115. Struct type Contact struct { Name string Phone string } The type name
  • 116. Struct type Contact struct { Name string Phone string } The type of “Contact “ is a struct
  • 117. Struct type Contact struct { Name string Phone string } Struct Field Name
  • 118. Struct type Contact struct { Name string Phone string } Field Type
  • 119. Struct Allocation func main() { p1 := Contact{Name: "Lisa", Phone: "1234"} p2 := Contact{"Mary", "2345"} fmt.Println(p1, p2) }
  • 120. 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"}
  • 121. Struct Allocation p1 := Contact{Name: "Lisa", Phone: "1234"} …Equals To… p1 := Contact{"Lisa", "1234"}
  • 122. Struct Allocation new(File) &File{} The expressions new(File) and &File{} are equivalent.
  • 123. Accessing Struct Fields contact1 := Contact{"Mary", "12345678"} fmt.Println(contact1.Name) Use “.” to access struct field
  • 124. 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)
  • 125. Accessing Struct Fields contact1 := Contact{"Mary", "12345678"} fmt.Println(contact1.Name) Pointer of type Contact contact2 := &Contact{"Mary", "12345678"} fmt.Println(contact1.Name)
  • 126. 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
  • 127. Custom Type
  • 128. Custom Types type Score int type ScoreMap map[string]int type NickName string
  • 129. Custom Types type Score int type ScoreMap map[string]int type NickName string type Score is a int type
  • 130. Custom Types type Score int ! func CalculateScore(a Score, b Score) Score { return a + b } Strict type of your data makes your application safer.
  • 131. 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
  • 132. 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
  • 133. Type Methods type NickName string ! func (self NickName) Say() { fmt.Println(self) }
  • 134. Type Methods type NickName string ! func (self NickName) Say() { fmt.Println(self) } Receiver
  • 135. Type Methods type NickName string ! func (self * NickName) Say() { fmt.Println(self) } You may also use the reference. (faster)
  • 136. Type Methods a := NickName("foo") a.Say() Allocate a string
  • 137. Type Methods a := NickName("foo") a.Say() Type cast to NickName
  • 138. Type Methods a := NickName("foo") a.Say() b := &a b.Say()
  • 139. Type Methods a := NickName("foo") a.Say() b := &a b.Say() Always use “.” to access fields or methods .
  • 140. Interface
  • 141. Interface • interface defines the requirement of the object method prototype. • you define the requirement and check the requirement in both compile-time and runtime.
  • 142. interface type Worker interface { Work() }
  • 143. interface type Worker interface { Work() } type SeedWorker struct{} ! func (self *SeedWorker) Work() { // work... }
  • 144. interface // accept anything implements // the interface of Worker func HandleData(worker Worker) { worker.Work() } ! func main() { HandleData(SeedWorker{}) HandleData(&SeedWorker{}) }
  • 145. 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.
  • 146. interface{} Given Struct Foo and Bar type Foo struct{} type Bar struct{}
  • 147. 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
  • 148. interface{} type anything interface{} var a anything = Foo{} var b anything = &Foo{} var c anything = &Bar{}
  • 149. interface{} type anything interface{} func AcceptAnything(a anything) { // do something } func main() { AcceptAnything(Foo{}) AcceptAnything(&Foo{}) AcceptAnything(&Bar{}) }
  • 150. Building Web Applications Using net/http
  • 151. Data Structure For Page $ mkdir wiki $ cd wiki $ vim page.go
  • 152. Data Structure For Page package main ! import ( "fmt" "io/ioutil" )
  • 153. Data Structure For Page type Page struct { Title string Body []byte }
  • 154. 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) }
  • 155. 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 }
  • 156. Build it! $ go build wiki.go
  • 157. Build it! $ go build wiki.go $ ./wiki This is a sample page.
  • 158. Introducing net/http package main ! import ( "fmt" "net/http" )
  • 159. 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:]) }
  • 160. 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:]) }
  • 161. 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)
  • 162. 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.
  • 163. 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”
  • 164. Introducing net/http http://localhost:8080/monkeys Hi there, I love monkeys!
  • 165. Using net/http package main ! import ( "fmt" "io/ioutil" "net/http" ) Import http package.
  • 166. 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
  • 167. 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
  • 168. 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.
  • 169. Using net/http func main() { http.HandleFunc("/view/", viewHandler) http.ListenAndServe(":8080", nil) }
  • 170. Build it! $ go build wiki.go
  • 171. Build it! $ $ $ $ vim test.txt go build wiki.go ./wiki curl http://localhost:8080/view/test
  • 172. 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) }
  • 173. The html/template package package main ! import ( "html/template" "io/ioutil" "net/http" )
  • 174. 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) }
  • 175. 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>
  • 176. 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