Go 語言的世界

宏觀, 安裝, 配置, 工程命令, 標準命令, 語法

開放設計Logo

Go的語言特性

開源

意味著版本與開發速度上的快速, 回顧看看C/C++ JAVA的歷史, 他們起初就不是開源

靜態 編譯型語言

降低直譯式語言所需要的型別檢查成本

跨平台?

其實叫做跨平台支援......

Garbage Collection

自動, 甚至允許手動

併發 Concurrency

可以先理解成比C語言的pthread輕量幾十倍的執行緒

goroutine, channel(後面會提)

物件導向?函數編程?

同時具備 物件導向 函數編程

物件導向

無繼承層次的輕量級物件導向

非侵入式接口(利於測試)

函數編程

函數類型叫做第一等類性(後面會說明)

惰性求值

Unication of Coding Style

優點

Compare with C/C++?

依賴管理明確

gc的能力使你不用過度干涉記憶體管理 大幅降低原始碼長度 開發效率提高

Compare with Java?

還要我說嗎?(去用Scala吧)

Compare with php?

我看$不爽可以吧XD

Compare with python/ruby?

效能

缺點

Compare with C/C++?

運行速度還不及

第三方函式庫的數量較少

不支援自已定義的泛型類型

併發其實有潛規則要遵守

不然等著創造坑自己踩進去吧

垃圾回收的改進

Hello World


```
package main

import "fmt"

func main() {
	fmt.Printf("Hello World!\n")
}
```
					

變數宣告

``` var x string = "Hello World" var y string y = "Hello World" z := "Hello World" ```

流程控制

``` // for i := 1 for i <= 10 { fmt.Println(i) i = i + 1 } // also for for i := 1; i <= 10; i++ { fmt.Println(i) } // add if for i := 1; i <= 10; i++ { if i%2 == 0 { fmt.Println(i, "even") } else { fmt.Println(i, "odd") } } // switch switch i { case 0: fmt.Println("Zero") case 1: fmt.Println("One") ```

陣列

``` // int array var x [5]int x[4] = 100 fmt.Println(x) //auto fill 0 with non-assignment // go through array var y [5]float64 y[0] = 98 y[1] = 93 y[2] = 77 y[3] = 82 y[4] = 83 var total float64 = 0 for i := 0; i < len(y); i++ { total += y[i] } fmt.Println("Total =", total) fmt.Println("Average =", total/float64(len(y))) //Mind len(y) is int // slice不固定大小的陣列( have append copy function....etc) z := make([]float64, 4, 10) fmt.Println(z) fmt.Println(y[1:4]) // same as python //append fmt.Println(append(z, 100, 200, 300, 400, 555, 666, 777, 888)) // Map, need memory malloc by using make elements := make(map[string]string) elements["H"] = "Hydrogen" elements["He"] = "Helium" elements["Li"] = "Lithium" elements["Be"] = "Beryllium" elements["B"] = "Boron" elements["C"] = "Carbon" elements["N"] = "Nitrogen" elements["O"] = "Oxygen" elements["F"] = "Fluorine" elements["Ne"] = "Neon" fmt.Println(elements["Li"]) fmt.Println(elements) // add if name, ok := elements["Li"] fmt.Println(name, ok) // Map in Map people := map[string]map[string]string{ "H": map[string]string{ "name": "Hydrogen", "state": "gas", }, "He": map[string]string{ "name": "Helium", "state": "gas", }, "Li": map[string]string{ "name": "Lithium", "state": "solid", }, "Be": map[string]string{ "name": "Beryllium", "state": "solid", }, "B": map[string]string{ "name": "Boron", "state": "solid", }, "C": map[string]string{ "name": "Carbon", "state": "solid", }, "N": map[string]string{ "name": "Nitrogen", "state": "gas", }, "O": map[string]string{ "name": "Oxygen", "state": "gas", }, "F": map[string]string{ "name": "Fluorine", "state": "gas", }, "Ne": map[string]string{ "name": "Neon", "state": "gas", }, } if el, ok := people["Li"]; ok { fmt.Println(el["name"], el["state"]) fmt.Println(el) ```

Function

Normal

``` func average(scores []float64) (float64) { total := 0.0 for _, value := range scores { total += value } return total / float64(len(scores)) } ```

多個input參數

``` func add(arguments ...int) int { total := 0 for _, value := range arguments { total += value } return total } ```

Generator

``` func makeEvenGenerator() func() uint { i := uint(0) fmt.Println("this only be called once") return func() (ret uint) { ret = i i += 2 return } } ```

遞迴

``` func factorial(x uint) uint { if x == 0 { return 1 } return x * factorial(x-1) } ```

defer

``` func first() { fmt.Println("first") } func second() { fmt.Println("second") } func main() { defer first() second() } //output: //second //first ```

指標

傳參數

``` func zero(x int) { x = 0 } func main() { x := 5 zero(x) fmt.Println(x) // x is still 5 } ```

傳參考

``` func zeroByRef(xPtr *int) { *xPtr = 0 } func main() { x := 5 zeroByRef(&x) fmt.Println(x) // x change to 0 } ```

傳指標變數

``` func two(xPtr *int) { *xPtr = 2 } func main() { xPtr := new(int) two(xPtr) fmt.Println(*xPtr) //xPtr is 2 } ```

交換變數的例子

``` func swap(x *int, y *int) { zPtr := new(int) *zPtr = *x *x = *y *y = *zPtr } func main() { var ( a = 2 b = 1 ) swap(&a, &b) fmt.Println("a =", a, "b =", b) } ``` Go千萬不要這樣實作

Go的變數參考可以略過那個tmp

``` func main() { var ( a = 2 b = 1 ) a, b = b, a fmt.Println("a =", a, "b =", b) } ```

Concurrency

Goroutine

``` func f(n int) { for i := 0; i < 10; i++ { fmt.Println(n, ":", i) amt := time.Duration(rand.Intn(250)) time.Sleep(time.Millisecond * amt) } } func main() { for i := 0; i < 10; i++ { go f(i) } var input string fmt.Scanln(&input) } ```

Goroutine IPC with channel

``` func tim(tim chan<- string) { // 傳入channal 然後一直將 "tim" send進去 tim這個channal for i := 1; ; i++ { // go's while ( true ) in C lang tim <- "tim" } } func randy(randy chan<- string) { //可以將傳入方向放在argument宣告 方便讀懂code 如果是雙向都要的時候就不指定方向 for i := 0; ; i++ { randy <- "randy" } } func receiveChannalAndPrint(leo <-chan string) { // 傳入 channal 然後每秒接收channal的內容 for { // another go's while ( true ) in C lang msg := <-leo fmt.Println(msg) time.Sleep(time.Second * 1) } } func main() { var c chan string = make(chan string) go tim(c) //相當於發起thread go randy(c) go receiveChannalAndPrint(c) var input string fmt.Scanln(&input) //故意讓主程式停住 } ```

Goroutine with Bufferd channel

``` chan1 := make(chan string, 10) chan2 := make(chan string, 10) go func() { for { chan1 <- "from tim" time.Sleep(time.Second * 1) } }() //很像Javascript吧XD go func() { for { chan2 <- "from randy" time.Sleep(time.Second * 1) } }() go func() { for { select { case msg1 := <-chan1: fmt.Println("message 1", msg1) case msg2 := <-chan2: fmt.Println("message 2", msg2) case <-time.After(time.Second): fmt.Println("timeout") default: fmt.Println("nothing") time.Sleep(time.Second * 1) } } }() ```

Package

使用自定義/內建/第三方函式庫

使用自己的要注意目錄結構(除非你另外放在github上import)

package math

``` package math // Finds the average of a series of numbers func Average(xs []float64) float64 { total := float64(0) for _, x := range xs { total += x } return total / float64(len(xs)) } ```

package main

``` package main import ( "./math" "fmt" ) func main() { xs := []float64{1, 2, 3, 4} avg := math.Average(xs) fmt.Println(avg) } ```

測試

沒有繼承問題

沒有侵入式接口問題

沒有非同步無法測試的問題(Javascript有實做一些方式幫助你處理)

方式你可能覺得跟Javascript超像

沒錯!! 因為它帶了Javascript的優良部份過來

Google提供的內建測試包 testing

說實在我沒有很喜歡XD

因為不太直觀

average.go

``` package math // Finds the average of a series of numbers func Average(xs []float64) float64 { total := float64(0) for _, x := range xs { total += x } return total / float64(len(xs)) } ```

average_test.go

``` package math import "testing" type testpair struct { values []float64 average float64 } var tests = []testpair{ {[]float64{1, 2}, 1.5}, {[]float64{1, 1, 1, 1, 1, 1}, 1}, {[]float64{-1, 1}, 0}, } func TestAverage(t *testing.T) { for _, pair := range tests { v := Average(pair.values) if v != pair.average { t.Error( "For", pair.values, "expected", pair.average, "got", v, ) } } } ```

Open Source的好處來了

跳坑玩家提供

https://github.com/stretchr/testify

add.go

``` package math // Finds the sum of a series of numbers func Add(xs []float64) float64 { total := float64(0) for _, x := range xs { total += x } return total } ```

add_test.go

``` package math import ( "github.com/stretchr/testify/assert" "testing" ) type addtestpair struct { values []float64 sum float64 } var addtests = []addtestpair{ {[]float64{1, 2}, 3}, {[]float64{1, 1, 1, 1, 1, 1}, 6}, {[]float64{-1, 1}, 0}, {[]float64{1.1, 2.3}, 3.4}, } func TestAdd(t *testing.T) { for _, pair := range addtests { v := Add(pair.values) assert.Equal(t, v, pair.sum, "they should be equal") } } ```

上次Google的朋友來提到的字串相加

就照著Google提供的規範走吧

``` package main import ( "fmt" "strings" ) func main() { fmt.Println( // true strings.Contains("test", "es"), // 2 strings.Count("test", "t"), // true strings.HasPrefix("test", "te"), // true strings.HasSuffix("test", "st"), // 1 strings.Index("test", "e"), // "a-b" strings.Join([]string{"a", "b"}, "-"), // == "aaaaa" strings.Repeat("a", 5), // "bbaa" strings.Replace("aaaa", "a", "b", 2), // []string{"a","b","c","d","e"} strings.Split("a-b-c-d-e", "-"), // "test" strings.ToLower("TEST"), // "TEST" strings.ToUpper("test"), ) } ```

End