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 | 在...之下 |
留言
張貼留言