Introducing Go - 筆記

簡述
這本書是一本入門的書,在這裡我會寫下屬於我自已的筆記,希望對你也有用。
(PS: 我是一個己經會寫程式的人,英文普通)
紀錄:
- 基本語法
 - 其他語言不同之處
 - 閱讀時會碰觸到的英文
 
觀念
Go 是一種強型別的語言。
一般來說盡量使用x := 5這種方式進行宣告
通常變數命名的風格用小寫駝峰
在Go中,參數傳遞的方式總是以copied(傳值)的方式
全域變數只能用var name type的型式宣告,無法使用x := 5的方式
Nan -> Not a Number (i.g. 0/0, +∞, -∞)
指令
查功能 go doc [package] [function]
->如果拿到 "go doc command not found" 嚐試這個指令安裝說明文件
-> go get golang.org/x/tools/cmd/godoc
語法
Go不支援三元運算子?:
字串除了"text"的形式,也可以是`text`
用+來連結字串
用_來接收用不到的回傳值
variable
var a = 5
a := 5
var (
    a = 5
    b = 10
    c = 15
)
for
// 1.只有條件
for 條件 {
    ...
}
// 2.含設初值與迭代
for 設初值; 條件; 迭代 {
    ...
}
// 3. 無窮迴圈
for 設初值; 條件; 迭代 {
    ...
}
if
if 條件 {
    ...
}
if 條件 {
    ...
} else if 條件 {
    ...
}
if 條件 {
    ...
} else {
    ...
}
if 賦初值; 條件 {
    ...
}
switch var {
    case val: ...
    case val: ...
    case val: ...
    case val: ...
    case val: ...
    case val: ...
    default: ...
}
    
array
陣列最後一個元素要有,
var x [5]int
x[4] = 100 // [0, 0, 0, 0, 100]
// -----
x := [5]int { // [1,2,3,4,5]
    1,2,3,4,5,
}
// -----
x := [5]int { // [1,2,3,0,0]
    1,2,3,
}
slices
是陣列的一部份(所以其實他是某個陣列的子集),其長度可變。
var x[]int // slices長度為0
// -----
x := make([]int, 5) // slices長度為5
// -----
x := make([]int, 5, 10) // slices長度為5,其父array長度為10
// -----
arr := [5]int{1,2,3,4} // 這是一個[1,2,3,4,0]的陣列
x := arr[0:3] // 這是一個[1,2,3]的切片(Slices)
append
var_slice = append(var_slice, var1, var2 ..)
append是slices之下的方法,只能對slices使用,無法對array使用。
這個方法會在slices的末端加上內容。(若其父array的長度不夠會建立另一個slices並把原本的內容copy過去,再加上新的內容)
slice1 := []int{1,2,3,4} // 這是一個[1,2,3,4]的slices
slice2 := apend(slice1, 4, 5) // [1,2,3,4,4,5]
copy
copy(var_slice_dst, var_slice_src) copy是slices之下的方法,只能對slices使用,無法對array使用。
這個方法會把src復製到dst中(只會復製長度足夠的部份)。
slice1 := []int{1,2,3,4} // [1,2,3,4] slices
slice2 := make([]int, 2) // [0,0] slices
copy(slice2, slice1)
// slice2 -> [1,2]
maps
關聯陣列。
var x map[string]int{} //x是一個string對應int的關聯陣列。
// -----
x := make(map[string]int)
x["a"] = 1
x["b"] = 2
x["c"] = 3
// map[a:1 b:2 c:3]
// ------
x := map[string]int {
    "a": 1,
    "b": 2,
    "c": 3,
}
maps返回兩個值: 取回來的值, 是否找到該值
// 承上 x => map[a:1 b:2 c:3]
val, isOk = x["a"] // 1, true
val, isOk = x["d"] // 0, false
2維的maps
// x是一個string對應map的關聯陣列
// x是一個string對應map ( string對應string關聯陣列 ) 的關聯陣列
x := map[string]map[string]string {
    "a": map[string]string {
        "sub-a1": "a1",
        "sub-a2": "a2",
    },
    "b": map[string]string {
        "sub-b1": "b1",
        "sub-b2": "b2",
    },
}
// map[a:map[sub-a1:a1 sub-a2:a2] b:map[sub-b1:b1 sub-b2:b2]]
函式
func foo(param) return val {
    ...
}
// 回傳多個值
func foo() (int, int) {
    ...
    return 1, 2
}
// 回傳有名字的變數
func foo() (r int) {
    r = 1
    return // 因為r是1, 所以會回傳1
}
variadic 可變參數 (...)
... 被用於函式的最後一個參數,他可以把多於的參數都放入最後一個參數中。
func add(x int, args ...int) int {
    total := 0
    for _, v := range args {
        total += v
    }
    return total
}
func main() {
    fmt.Println(add(1, 2, 3, 4, 5)) // 14
}
也可以利用...將陣列展開並放到可變參數中
func add(x int, args ...int) int {
    total := 0
    for _, v := range args {
        total += v
    }
    return total
}
func main() {
    xs := []int{1,2,3,4,5}
    fmt.Println(add(1,xs...)) // 14
    fmt.Println(add(xs...)) // error "not enough arguments in call to add"
}
內建函式
range
range 被用在 for 中 用來迭代array, slices, maps,他會返回 index, value 或 key, value
作用域scope
像是javascript,從裡往外找。
閉包closure
func countFactory() func()(int) {
    i := 0
    return func() (int) {
        i++
        return i
    }
}
func main() {
    countFunc := countFactory()
    fmt.Println(countFunc()) // 1
    fmt.Println(countFunc()) // 2
    countFunc2 := countFactory()
    fmt.Println(countFunc2()) // 1
    fmt.Println(countFunc()) // 3
    fmt.Println(countFunc2()) // 2
    fmt.Println(countFunc2()) // 3
}
defer (推遲)
用來將某個語句推遲到該函式的return前執行。(常用在file) 就算發生panic,defer還是會執行!
f, _ := os.Open(filename)
defer f.Close() // 這樣就不用擔心忘記close了,也不會讓file的code到處都是
- defer會記住當下的狀態
 - defer會先進後出
 
panic 和 recover
有點像是php的throw Exception, try catch,但是用法上有些區別。
首先發生panic,然後可以利用recover來取得panic傳入的錯誤訊息。
// panic
panic("PANIC") // 從這裡就會跳出Error
fmt.Println("123") // 不會被執行,因為前一行panic了
// -----
// 錯誤的使用
panic("Error Msg")
str := recover() // 不會執行
fmt.Println(str) // 不會執行
一般來說,我們會想知道panic跳出什麼錯誤,但是panic會中斷函式,所以我們會利用defer的特性,抓到panic跳出的錯誤訊息。
defer func() {
    str := recover()
    fmt.Println(str) // 印出panic
}()
panic("panic")
指標 *, &
基本同C語言 * -> 取值, & -> 取址
new
宣告一個類型的變數並回傳其地址 xPtr := new(int)
structs 結構
基本同C語言
type Point struct {
    x int
    y int
}
x := Point{1, 2} // 照順序賦值
fmt.Println(x) // {1 2}
fmt.Println(x.x) // 1
fmt.Println(x.y) // 2
// ------
x := Point{y:1, x:2} // 照key賦值
fmt.Println(x) // {2 1}
methods for struct 結構的方法
一般來說我們會新增一個方法,並接收一個struct type的參數,但是在Go中可以為struct 新增方法,讓使用上更直覺。
type Point struct {
    x int
    y int
}
func (p *Point) plusPoint() int {
    return p.x + p.y
}
func main() {
    x := Point{1, 2}
    fmt.Println(x.plusPoint()) // 3
}
embedded types 嵌套結構
結構中可以含有另一個結構,用例子的方式來解釋。
先有一個結構->人類,有一個說出自己性別的方法TalkSex()。
type Human struct {
    Sex bool
}
func (p *Human) TalkSex() {
    if p.Sex {
        fmt.Println("I am male.")
    } else {
        fmt.Println("I am female.")
    }
}
func main() {
    x := Human{Sex: true}
    fmt.Println(x) // {true}
    x.TalkSex() // I am male.
}
現在有一個新的結構Person,Person結構中包含了Human。
// 結構上成立,但語意不成立 (我們會說一個人含有名字這個屬性,但不會說一個人含有人類的屬性)
// "一個人"含有"人類"的屬性
type Human struct {
    Sex bool
}
func (p *Human) TalkSex() {
    if p.Sex {
        fmt.Println("I am male.")
    } else {
        fmt.Println("I am female.")
    }
}
type Person struct {
    Human Human
    Name string
}
func main() {
    x := Person{Human{Sex: true}, "jack"}
    fmt.Println(x) // {{true} jack}
    x.Human.TalkSex() // I am male.
}
一般來說,我們會說Person是個Human( Person is-a Human) // 一個人 是個 人類
但是在上述範列中變成"一個人 含有 人類",所以當我們需要is-a這種關系的時候會這樣使用
// "一個人" 是 "人類"
type Human struct {
    Sex bool
}
func (p *Human) TalkSex() {
    if p.Sex {
        fmt.Println("I am male.")
    } else {
        fmt.Println("I am female.")
    }
}
type Person struct {
    Human // 注意這裡,這裡說明了 Person is-a Human 的關系
    Name string
}
func main() {
    x := Person{Human{Sex: true}, "jack"}
    fmt.Println(x) // {{true} jack}
    x.TalkSex() // I am male.
    x.Human.TalkSex() // I am male. // 也可以用這樣用(不常用)
}
區別 含有某個屬性 與 是屬於(is-a)很有必要,這會大大的影響可讀性,與直覺上函式的使用方法。
- 是否使用 embedded types 取決於你要用
is-a(用),還是has(不該用)的關系。 
interface
interface定義方法集合(method set)。
type Shape interface { // 裡面應只有一堆方法
    calArea() float64
}
// 任何struct只要有calArea() float64,就算是Shape
只要某個struct的方法對應的上,那就算是該interface。
(把interface想像成濾網,只要struct的方法與interface一模一樣,就通過了)
type Rectangle struct {
    x1, y2, x2, y2 float64
}
func (r *Rectangle) calArea() float64 {
    l := distance(r.x1, r.y1, r.x1, r.y2)
    w := distance(r.x1, r.y1, r.x2, r.y1)
    return l * w
}
// 因為Rectangle這個結構有calArea() float64,所以算也屬於Shape這interface。
type Circle struct {
    x1, y2, x2, y2 float64
}
func (c *Circle) calArea() float64 {
    return math.Pi * c.r * c.r
}
// 因為Circle這個結構有calArea() float64,所以算也屬於Shape這interface。
interface跟struct一樣,可以被當成參數傳遞。
這讓不同的struct,可以因為interface的關系被傳入到同一個函式中。
func sumArea(shapes ...Shape) float64 {
    area := 0.0
    for _, s := range shapes {
        // 只能使用s.calArea(),不能使用原struct的屬性。
        // 因為你代入的是Shape這個interface,而該interface只有calArea()這個方法。
        area += s.calArea() 
    }
    return area
}
interface也可以被放到struct中。
type ALotShape struct {
    shapes []Shape
}
// 若是我們為這個struct加上 calArea() float64,那他也算是Shape這interface。
func (a *ALotShape) calArea() float64 {
    area := 0.0
    for _, s := range a.shapes {
        area += s.calArea()
    }
    return area
}
所以
- 透過為struct增加method來符合某個interface
 - 透過interface來接收多個不同種類卻有相同方法的struct
 - interface關注的是方法,這使在開發程式的時候不需要去關注struct的細節。
 - interface與struct只在方法上偶合,所以更動struct的時候不必在意結構與繼承的關系。
 
語法糖
x := 5, var x = 5 -> Go會自動判斷賦值的型別,並宣告給x。arr[0:] 等同於arr[0:len(arr)]arr[:5]等同於arr[0:5]arr[:]等同於arr[0:len(arr)]
英文單字
| 英文 | 中文 | 
|---|---|
| distributed | 分散式 | 
| domains | 領域 | 
| simplicity | 簡單 | 
| low barrier | 低門檻 | 
| abundance | 豐富 | 
| geared towards | 面向 | 
| exhaustive | 全面詳盡的 | 
| trackle "something" | 解決 .. | 
| rudimentary | 初級的 | 
| concurrency | 並發 | 
| preceding chapters | 上一章 | 
| significantly | 顯著地 | 
| conventions | 公約/約定 | 
| typographical | 印刷的 | 
| literally | 字面上地 | 
| determined | 決定的 | 
| advanced features | 高級功能 | 
| robust | 健全的 | 
| prior | 先/事先的 | 
| concise | 簡潔的/簡明扼要的 | 
| consulting | 諮詢 | 
| intimidating | 可怕的 | 
| mechanism | 機制 | 
| altering | 改變 | 
| corresponding | 相應的 | 
| interact | 相互影響 | 
| identical | 完全相同的 | 
| subsequent | 隨後的 | 
| pedantic | 迂腐的 | 
| no tolerance | 無容忍 | 
| parentheses | 括號 | 
| curly braces | 大括號 | 
| terminology | 術語 | 
| deliberately | 故意地 | 
| nevertheless | 儘管如此地 | 
| categorize | 分類 .. | 
| grasp | 把握 .. | 
| perspectives | 觀點 | 
| philosophers | 哲學家 | 
| distinction | 區別 | 
| cumbersome | 麻煩的 | 
| decimal | 十進制 | 
| representation | 表示 | 
| inexact | 不準確的 | 
| occasionally | 偶爾地 | 
| arithmetic | 算術 | 
| precisions | 精度 | 
| respectively | 分別地 | 
| remainder | 餘數 | 
| sufficient to | 足以去 .. | 
| sophisticated | 複雜的 | 
| individual | 各別的 | 
| backtick | 反引號 ` | 
| concatenation | 串聯,串起 | 
| formulas | 公式 | 
| involve | 包括 .. | 
| manipulation | 操 | 
| transformation | 轉型 | 
| foundation | 基礎 | 
| algebra | 代數 | 
| subtle | 微妙的 | 
| dendency to | 傾向 .. | 
| theorem | 定理 | 
| infer | 推斷 | 
| informal | 非正式的 | 
| phenomenon | 現像 | 
| semantically | 語義上地 | 
| idiomatic | 慣用語的 | 
| worthwhile | 值得的 | 
| pursuit | 追求 | 
| phrase | 短語 | 
| specification | 規範 | 
| lexically | 詞彙上地 | 
| essentically | 本質上地 | 
| evaluate | 評估 | 
| divisible | 可約分的 | 
| slices | 切片 | 
| segment | 部分/片段 | 
| capacity | 容量 | 
| subroutine | 子程序 | 
| procedure | 程序 | 
| independent section | 獨立的部份 | 
| callee | 被調用者 | 
| variadic | 可變參數 | 
| ellipsis | 省略 | 
| precisely | 恰恰地/剛剛好地 | 
| persists | 持續存在 | 
| recursion | 遞迴 | 
| tempt to do | 情不自禁的去做 .. | 
| hence | 因此 | 
| rarely | 很少地 | 
| collapse fields | 折疊字段 | 
| intuitively | 直覺地 | 
| accident | 事故 | 
| commonplace | 常見的/普通的 | 
| accidental | 偶然的 | 
| explicit | 明確的 | 
| poligons | 多邊形 | 
| taxonomy | 分類 | 
| incidental details | 附加細節 | 
| embodied | 體現的 | 
| utilize | 利用 | 
| overlapping | 重疊的/重覆的 | 
| succinct | 簡潔的 | 
| from scratch | 從頭開始 | 
| cryptography | 密碼學 | 
| efficient | 高效的 | 
| underneath | 在...之下 | 
留言
張貼留言