1. Keyword
-
Golang僅有 25 個保留關鍵字,體現了 golang 語法規則的簡潔性
-
保留關鍵字不能用作常量、變數、函式名、以及結構欄位等識別符號
2. Operator
-
Golang 中沒有乘冪和絕對值運算子,對應的是標準庫 math 裡的 Pow、Abs 函式實現
-
一元運算子的優先順序最高
-
二元運算子有五個級別從高到低分別是:
-
相同優先順序的二元運算子,從左到右依次計算
-
使用二元運算子,除了位移操作以外,運算元型別必須相同,如果其中一個是無顯式型別宣告的常量,那麼該常量運算元會自動轉型
-
位移右運算元必須是無符號整數,或者可以轉換的無顯式型別常量
-
如果是非常量位移表示式,那麼會優先將無顯式型別的常量左運算元轉型
-
位運算子
Attention:
-
在 golang 中自增、自減不再是運算子,而是作為獨立語句存在,不能用於表示式使用
-
表示式通常式 求值程式碼,可以作為右值或者引數使用,而語句完成一個行為,比如 if、 for 程式碼塊,表示式可以作為語句使用,但是語句卻不能當作表示式
Pointer:
-
不能將記憶體地址與指標混為一談
-
記憶體地址是記憶體中每個位元組單元的唯一編號,而指標則是一個實體
-
指標會被分配記憶體空間,相當於一個專門用來儲存地址的整型變數
-
取值運算子 “ & ” 用於獲取物件地址
-
指標運算子 “ * ” 用於間接引用目標物件
-
二級指標 **T, 如果包含包名則寫成 *package.T
-
並非所有物件都能進行取地址操作,但是變數總是能夠正確返回 (addressable),指標運算子為左值時,我們可更新目標物件狀態,為右值時,我們可以獲取目標物件狀態
-
指標支援相等運算子,但不能做加減法運算和型別轉換,如果兩個指標指向同一地址,或者都為nil,那麼它們相等
Attention:
-
可以透過 unsafe.Pointer 將指標轉換為 uintptr 後進行加減法運算,但可能會導致非法訪問
-
Pointer 類似C 語言中的 void* 萬能指標, 可以用來轉換指標型別。他能安全持有物件和物件成員,但是 uintptr 不行。uintptr 僅是一種特殊型別, 並不用於目標物件, 無法組織垃圾回收器回收物件記憶體
-
Golang 中沒有專門指向成員的 " -> " 運算子, 統一使用 “ . ” 選擇表示式
Zero - size:
-
零長度 (zero - size)物件的地址是否相等和具體的實現版本有關,但是肯定不等於 nil
-
即使長度為 0 ,可該物件依然時合法存在的,擁有合法的記憶體地址,這與 nil 語義完全不同
-
在 runtime/malloc.go 裡有個 zerobase 全域性變數, 所有透過 mallocgc 分配的零長度物件都使用該地址
3. Initialization
-
對複合型別(slice、array、map、struct)變數初試化時,有一些語法限制
-
初始化表示式必須包含型別標籤
-
左花括號必須在型別尾部,不能另起一行
-
多個成員初始值以逗號分割
-
允許多行,但每行以逗號或者右花括號結束
4. Flow Control
-
Golang 精簡(合併)了流控制語句,雖然某些時候不夠便捷,但是夠用
-
if...else...
-
條件表示式值必須是 bool 型別,可以省略括號,但是左花括號不能另起一行
-
支援初始化語句,可定義塊區域性變數或執行初始化函式
Attention:
-
-
上示例中,if 塊承擔了兩種邏輯:錯誤處理和後續正常操作。
基於重構原則,我們應該保持程式碼塊功能的單一性
如此,if 塊僅完成條件檢查和錯誤處理,相關正常邏輯保持在同一層次。
這樣做便於程式碼的閱讀,也提升了程式碼的可維護性,更利於拆分重構
如果需要在多個條件塊中使用區域性變數,那麼只能保留原層次,或者直接使用外部變數
對於某些過於複雜的組合條件,建議將其重構為函式
函式呼叫雖然有一些效能損失,但是卻讓主流程變得更加清爽,更易於測試,改善程式碼 可維護性
Notice:
將流程和區域性細節分離是一個很好的習慣
不同的變化因素被分隔在各自獨立單元(函式或者模組)內,可以避免修改時造成關聯錯誤,減少患“ 肥胖症 ”的函式數量
-
switch
-
條件表示式支援非常量值,使得 golang 比C更加靈活。相比於if表示式, switch值列表更加簡潔
-
編譯器對if、switch 生成的機器指令可能完全相同,所謂誰的效能更好看具體情況而定
-
switch 同樣支援初始化語句,按照從上到下,從左到右匹配case執行,只有全部匹配失敗時才會執行default塊
-
無需顯式執行 break 語句, case執行完畢後自動中斷,如要繼續訪問後續 case (原始碼順序),需要執行 fallthrough 關鍵字,但是不再進行條件表示式匹配
Attention:
-
fallthrough 必須放在 case 塊的結尾,可被 break 語句阻止
-
如果 fallthrough 放在 default 後面,因為會按照原始碼執行順序執行所以不會執行 default 導致錯誤
Notice:
-
某些時候,switch 被用來替換 if 語句, 被省略的 switch 條件表示式預設為 true,繼而與 case 比較表示式結果匹配
-
switch 有時候也用於介面型別匹配
-
-
for
-
golang 中僅有 for 這一種迴圈語句
-
初始化語句僅能被執行一次,條件表示式中如果有函式呼叫,要先確認是否會被重複執行
-
如果存在重複執行的函式,則可能會被編譯器最佳化掉,也可能是動態結果須每次執行確認
-
處理上述問題的辦法是,建立臨時變數儲存該函式結果
-
使用 for...range 完成資料迭代支援 string、array、pointer、array pointer、slice、map、channel等型別,返回索引、鍵值資料
-
允許返回單指(次數),或用 “ _ ” 忽略
-
無論是 for 還是 for...range 迭代,其中定義的區域性變數都會被重複使用(地址相同),但這樣會對閉包有一些影響
Attention
-
使用 range 時會先複製要迭代的目標資料,再在複製體中區取值,所以會影響陣列的 range 使用因此建議使用陣列指標或者切片型別去代替
-
在 range 的複製問題中,string、slice 的基本結構都是很小的結構體,而 map、channel 本身時指標封裝,它們的複製成本都很小,無須專門最佳化
-
如果 range 的目標表示式時函式呼叫,那也僅被執行一次
-
-
goto、continue、break
-
使用 goto 前,需要先定義標籤。標籤區分大小寫,且未使用的標籤會引發編譯錯誤
-
不能使用 goto 跳轉到其他函式或者內層程式碼塊內
-
break 和 continue 用於終端程式碼塊的執行