前言
這篇文章主要來紀錄 Golang 的學習紀錄,使用的教材是碁峰出版的精通 Go 程式設計。
正文
程式結構
名稱
Go 的命名原則: 以 字母 or 底線 開頭
Go 有若干個關鍵字,只能用於語法中使用,因此他們不能拿來當作名稱!
break, default, func, interface, select, case, defer, go, map, struct, chan, else, goto, package, switch, const, fallthrough, if, range, type, continue, for, import, return, var
但是 Go 有一些 預先宣告 的名稱,是可以拿來重新宣告的!
常數: true false iota nil
型別: int uint float bool byte rune string error
函式: make len cap new append copy close delete complex real imag panic recover
名稱的第一個字母用來決定可見度是否可以跨越套件的邊界,如果名稱是以大寫字母開頭,在套件外是可見且可存取的,比方說 fmt 的 Print,套件的名稱本身永遠是小寫。
名稱長度無限制,但 Golang 的 convention 是習慣使用 短名稱 及 **駱駝式(Camel Case)**。比方說,變數 i 比 theLoopIndex 常見,或是習慣使用 aNewFunc
而不是 a_new_func
。
但這一切都是使用習慣,在業界大多是還是以部門的開發文化為主!
宣告
主要有四種宣告 var
const
type
func
,以下面的程式碼來做介紹
1 | package main |
boilingF
屬於套件層級的宣告,而 f, c 屬於區域宣告。
變數
透過 var
來宣告特定型別的變數,格式為 var name type = expression
,其中 型別
或是 = expression
兩者之一是可以省略的,但不能全部省略,如果省略型別,則會以 expression 來決定型別,如果省略 expression,則會以型別的零值來決定數值。
E.g.
數字 -> 0
布林值 > false
字串 > “”
interface & 參考型別 > nil
集合型別(array & struct) > 所有元素 or 欄位均為零值
零值的機制是為了確保變數有個正確定義的值,Go 沒有所謂的為定義變數,這麼做是為了不額外花心力的前提下確保合理的邊界條件。
1 | var s string |
短變數宣告
以省略 var 的方式來宣告變數,格式為 name:=expression
,其中 name 的型別是由 expression 來決定。
短變數宣告中,必須至少宣告一個新的變數
1 | a, b := 1, 2 |
指標
指的是變數的位址,因此指標是所儲存值的位置。 並非每一個數值都會有位址,但 **每個變數都會有位址
**! 因此我們可以使用指標來讀取或是修改這些值
組合型別變數 - struct or array 的元素也都具有位址
任何型別的指標,其零值皆為 nil。指標也可以拿來互相比較,當兩個指標在同一個變數或均為 nil 才會相等。
1 | var x, y int |
在函式中可以安全的回傳區域變數的位址,對於 foo 內的區域變數 v,在呼叫完畢之後,還是能透過指標來指向他
1 | func main() { |
1 | var n = flag.Bool("n", false, "omit trailing newline") |
new 函式
透過內建的 new
來建構變數,建構一個 x型別的不具名變數**,也就是說 new(x) 是以 x 的零值去做初始化,並回傳 *x 型別的位址。
1 | p := new(int) |
變數生命週期
指派
透過 指派 讓變數所保存的值進一步變化
1 | x = 1 // 具名變數 |
資料組的指派
可以在同一行中去指派多個資料
1 | x, y = y, x |
1 | func main() { |
型別宣告
type 賦予固有的型別一個新的 具名型別,格式為 type name underlying-type
,通常 name 會以大寫的方式呈現。
1 | // 以 float64 去定義新的型別 Celsius, Fahrenheit |
基本資料型別
Go 的型別分成四種:
- 基本型別: 數字、字串、布林
- 集合型別: 陣列、Struct
- 參考型別: 指標、slice、map、函式、channel
- 介面型別
整數
可以分成 正負號 & 無正負號 & 四種大小 8、16、32、64 的組合。
要注意不同型別的變數不能做運算
1 | var apples int32 = 1 |
複數
有 complex64
& complex128
這兩種。
1 | var x complex128 = complex(1, 2) |
字串
嘗試存取範圍外的位元組會導致 panic
1 | str := "a pine apple" |
可以透過 slice 來取得特定範圍的字串內容
1 | str := "a pine apple" |
常數
常數宣告可以指定 型別 與 值,在沒有明確指定型別時,型別由運算式的右手邊決定。
iota 常數產生器
const 宣告可使用 iota 常數產生器
,這種型別也可以稱為列舉 Enum
。
1 | type Weekday int |
1 | type Flags int |
組合型別
陣列
是由零到多個特定型別元素所組成的,因為它是固定長度,故陣列很少在 Go 中使用,反而可變大縮小的 slice 更有彈性。
陣列變數以元素型別的零值來做初始化
1 | var arr1 [3]int = [3]int{1, 2, 3} |
也可以使用 ...
來代替長度
1 | arr2 := [...]int{1, 2, 3} |
陣列的長度大小也是用來判定型別是否相同的一部分因素,因此,[3]int
與 [4]int
兩者是不同的型別。
1 | arr1 := [3]int{1, 2, 3} |
1 | 建立 int 型別的新型別 Currency |
雜湊表 map
雜湊表是一個無排序的 key/value 群組,在這群組中的鍵值必定唯一,其表示方法為 map[K]V
,其中 K & V 所分別代表的是鍵與值的型別。所有鍵 & 值 均為同一型別,但兩者不一定要同一型別。
Goroutine & Channel
每個並行執行的都被稱為 goroutine