Happy Go Programming

4,252
-1

Published on

golang, go, programming, web applications.

Happy Go Programming

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

    Clipping is a handy way to collect important slides you want to go back to later.

×