Go語言規範彙總

統一規範篇

合理規劃目錄

本篇主要描述了公司內部同事都必須遵守的一些開發規矩,如統一開發空間,既使用統一的開發工具來保證代碼最後的格式的統一,開發中對文件和代碼長度的控制,必須經過go語言自帶的檢測機制等。

【原則1.1】合理規劃目錄,一個目錄中只包含一個包(實現一個模塊的功能),如果模塊功能複雜考慮拆分子模塊,或者拆分目錄。

GOPATH設置

【建議1.2】使用單一的 GOPATH

import 規範

【規則1.3.1】在非測試文件(*_test.go)中,禁止使用 . 來簡化導入包的對象調用。

【規則1.3.2】禁止使用相對路徑導入(./subpackage),所有導入路徑必須符合 go get 標準。

【建議1.3.3】建議使用goimports工具或者IDE工具來管理多行import

代碼風格

【規則1.4.1】提交代碼時,必須使用gofmt對代碼進行格式化。

【規則1.4.2】提交代碼時,必須使用golint對代碼進行檢查。

【建議1.4.3】提交代碼前,必須使用go vet對代碼進行檢查。

大小約定

【建議1.5.1】單個文件長度不超過500行。

【建議1.5.2】單個函數長度不超過50行。

【規則1.5.3】單個函數圈複雜度最好不要超過10,禁止超過15。

【規則1.5.4】單行語句不能過長,如不能拆分需要分行寫。一行最多120個字符。

【建議1.5.5】函數中縮進嵌套必須小於等於3層。

【原則1.5.6】保持函數內部實現的組織粒度是相近的。

命名篇

本篇以開發時從上往下的順序既:開發前約定的基本命名規範、包、常量、變量、結構體、參數、返回值的順序講解了開發中各個環節的命名規範。

基本命令規範

【規則2.1.1】需要註釋來補充的命名就不算是好命名。

【規則2.1.2】使用可搜索的名稱

【規則2.1.3】做有意義的區分

項目目錄名

【規則2.2.1】目錄名必須爲全小寫單詞,允許加中劃線‘-’組合方式,但是頭尾不能爲中劃線。

【建議2.2.2】雖然允許出現中劃線,但是儘量避免或少加中劃線。

包名

【原則2.3.1】取名儘量採取有意義的包名,簡單和可閱讀。

【規則2.3.2】包名必須全部爲小寫單詞,無下劃線,越短越好。儘量不要與標準庫重名。

【規則2.3.3】禁止通過中劃線連接多個單詞的方式來命名包名。

【建議2.3.4】包名儘量與所在目錄名一致,引用時比較方便。

文件名

【規則2.4.1】文件名必須爲小寫單詞,允許加下劃線‘_’組合方式,但是頭尾不能爲下劃線

【建議2.4.2】雖然允許出現下劃線,但是儘量避免。

【建議2.4.3】文件名以功能爲指引,名字中不需再出現模塊名或者組件名。

常量

【規則2.5.1】常量&枚舉名採用大小寫混排的駝峯模式(Golang官方要求),不允許出現下劃線

【建議2.5.2】按照功能來區分,而不是將所有類型都分在一組,並建議將公共常量置於私有常量之前

【規則2.2.3】如果是枚舉類型的常量,需要先創建相應類型

【建議2.5.4】如果模塊的功能較爲複雜、常量名稱容易混淆的情況下,爲了更好地區分枚舉類型,可以使用完整的前綴

變量

變量申明

【規則2.6.1】變量命名基本上遵循相應的英文表達或簡寫,在相對簡單的環境(對象數量少、針對性強)中,可以將一些名稱由完整單詞簡寫爲單個字母

變量命名慣例

【規則2.6.2】變量名稱一般遵循駝峯法,並且不允許出現下劃線,當遇到特有名詞時,需要遵循以下規則:

  • 如果變量爲私有,且特有名詞爲首個單詞,則使用小寫,如:apiClient
  • 其它情況都應當使用該名詞原有的寫法,如 APIClient、repoID、UserID

【規則2.6.3】不要使用_來命名變量名,多個變量申明放在一起

【規則2.6.4】在函數外部申明必須使用var,不要採用:=,容易踩到變量的作用域的問題。

全局變量名

【規則2.6.5】全局變量必須爲大小寫混排的駝峯模式,不允許出現下劃線。首字母根據作爲範圍確定大小寫。

【建議2.6.6】儘量避免跨package使用全局變量,儘量減少全局變量的使用。

局部變量名

【規則2.6.7】局部變量名必須爲大小寫混排,且首字母小寫,不能有下劃線。

循環變量

【建議2.6.8】for循環變量可以使用單字母。

結構體(struct)

【規則2.7.1】struct申明和初始化格式採用多行

【規則2.7.2】結構體名必須爲大小寫混排的駝峯模式,不允許出現下劃線,可被包外部引用則首字母大寫;如僅包內使用,則首字母小寫。

【建議2.7.3】結構名建議採用名詞、動名詞爲好。

接口名

【規則2.8.1】接口名必須爲大小寫混排,支持包外引用則首字母大寫,僅包內使用則首字母小寫。不能有下劃線,整體必須爲名詞。

【建議2.8.2】單個函數的接口名以”er”作爲後綴。

函數和方法名

【規則2.9.1】函數名必須爲大小寫混排的駝峯模式

【建議2.9.2】函數名力求精簡準確,並採用用動詞或動詞短

【規則2.9.3】方法接收名必須爲大小寫混排,首字母小寫。方法接收者命名要能夠體現接收者對象。

【建議2.9.4】接收者名通常1個或者2個字母就夠,最長不能超過4個字母。

【建議2.9.5】接收者名不要使用me,this 或者 self 這種泛指的名字。

【建議2.9.6】定義方法時,如果方法內不會直接引用接收者,則省略掉接收者名。

參數名

【規則2.10】參數名必須爲大小寫混排,且首字母小寫,不能有下劃線。

返回值

【規則2.11.1】返回值如果是命名的,則必須大小寫混排,首字母小寫。

【建議2.11.2】 函數的返回值應避免使用命名的參數。

開發篇

本篇主要是講解開發中各個環節的開發規範和對一些代碼的優化寫法。在本文中有一些特別標黃的建議,我真的建議你好好看看那些代碼,因爲那可能對你提高代碼開發會很有幫助。

【建議3.1.1】項目倉庫中包含全量的代碼

【建議3.1.2】建議採用 Glide 來管理第三方包

魔鬼數字

【規則3.2】代碼中禁止使用魔鬼數字。

常量 & 枚舉

【建議3.3.1】 爲整數常量添加 String() 方法

【建議3.3.2】讓 iota 從 a +1 開始增量

結構體

【規則3.4.1】對於要使用json轉換的結構體代碼,變量名必須爲大寫,否則你只會得到一個爲空的對象

【建議3.4.2】 在初始化結構體時使用帶有標籤的語法

【建議3.4.3】將結構體的初始化拆分到多行

運算符

【規則3.5】運算符前後、逗號後面、if後面等需有單空格隔開。

函數

【原則3.6.1】保持函數內部實現的組織粒度是相近的。

【建議3.6.2】 返回函數調用

【建議3.6.3】 withContext 封裝函數

參數

【建議3.7.1】參數按邏輯緊密程度安排位置, 同種類型的參數放在相鄰位置。

【建議3.7.2】避免使用標識參數來控制函數的執行邏輯。

【建議3.7.3】參數個數不要超過5個

返回值

【規則3.8.1】函數返回值個數不要超過3個。

【建議3.8.2】如果函數的返回值超過3個,建議將其中關係密切的返回值參數封裝成一個結構體。

註釋

【原則3.9.1】編寫代碼首先考慮如何代碼自我解釋,然後纔是添加註釋進行補充說明

【原則3.9.2】註釋的內容要清楚、明瞭,含義準確,防止註釋二義性。

【原則3.9.3】在代碼的功能、意圖層次上進行註釋,即註釋用於解釋代碼難以直接表達的意圖,而不是重複描述代碼。

【規則3.9.4】所有導出對象都需要註釋說明其用途;非導出對象根據情況進行註釋。必須時,應該說明值的取值範圍,及默認值。

【規則3.9.5】註釋的單行長度不能超過 80 個字符。

【規則3.9.6】註釋需要緊貼對應的包聲明和函數之前,不能有空行、

【規則3.9.7】非跨度很長的註釋,儘量使用 // 方式。

【規則3.9.8】避免多餘的空格,兩句註釋之間保持一個空格。

【原則3.9.9】註釋第一條語句應該爲一條概括語句,並且使用被聲明的名字作爲開頭。

【建議3.9.10】//與註釋的文檔之間空一格。

【規則3.9.11】每個程序包都應該有一個包註釋,一個位於package子句之前的塊註釋。

【規則3.9.12】不要依靠用空格進行對齊。

【建議3.27】類型定義一般都以單數信息描述。

【建議3.9.13】函數聲明處註釋描述函數功能、性能及用法,包括輸入和輸出參數、函數返回值、可重入的要求等;定義處詳細描述函數功能和實現要點,如實現的簡要步驟、實現的理由、設計約束等

【建議3.9.14】如果函數或者方法爲判斷類型(返回值主要爲bool類型),則以 returns true if 開頭。

錯誤

【原則3.10.1】錯誤處理的原則就是不能丟棄任何有返回err的調用,不要採用_丟棄,必須全部處理。接收到錯誤,要麼返回err,要麼實在不行就panic,或者使用log記錄下來

【規則3.10.2】error的信息不要採用大寫字母,儘量保持你的錯誤簡短,但是要足夠表達你的錯誤的意思。

【規則3.10.3】導出的錯誤變量的命名,以Err開始,如ErrSomething,無需導出的錯誤變量命名,以Error作爲後綴,如specificError

【規則3.10.4】公共包內禁止使用panic,如果有panic需要內部recover並返回error。

其他

【建議3.11.1】在代碼中編寫字符串形式的json時,使用反單引號,而不是雙引號。

【規則3.11.2】相對獨立的程序塊之間、變量說明之後必須加空行,而邏輯緊密相關的代碼則放在一起。

【規則3.11.3】儘早return:一旦有錯誤發生,馬上返回。

【建議3.11.4】禁止出現2處及以上的重複代碼。

【建議3.11.5】if條件判斷, 同時使用超過3個表達式以上的時候, 使用switch替代。

【建議3.11.6】定義bool變量時,要避免判斷時出現雙重否定,應使用肯定形式的表達式。

【建議3.11.7】for循環初始值從0開始,判斷條件使用<無等號的方式。

【建議3.11.8】長句子打印或者調用,使用參數進行格式化分行

【建議3.11.9】 將 for-select 封裝到函數中

【建議3.11.10】把 slice、map 等定義爲自定義類型

【建議3.11.11】 爲訪問 map 增加 setter,getters

參數傳遞

【建議3.11.12】 對於少量數據,不要傳遞指針

【建議3.11.13】 對於大量數據的 struct 可以考慮使用指針

【建議3.11.14】 傳入的參數是 map,slice,chan 不要傳遞指針,因爲 map,slice,chan 是引用類型,不需要傳遞指針的指針

注意閉包的調用

【原則3.11.15】在循環中調用函數或者goroutine方法,一定要採用顯示的變量調用,不要再閉包函數裏面調用循環的參數

優化篇

本篇的意義是爲開發提供一些經過驗證的開發規則和建議,讓開發在開發過程中避免低級錯誤,從而提高代碼的質量保證和性能效率

質量保證

代碼質量保證優先原則

【原則4.1.1】代碼質量保證優先原則:
(1)正確性,指程序要實現設計要求的功能。
(2)簡潔性,指程序易於理解並且易於實現。
(3)可維護性,指程序被修改的能力,包括糾錯、改進、新需求或功能規格變化的適應能力。
(4)可靠性,指程序在給定時間間隔和環境條件下,按設計要求成功運行程序的概率。
(5)代碼可測試性,指軟件發現故障並隔離、定位故障的能力,以及在一定的時間和成本前提下,進行測試設計、測試執行的能力。
(6)代碼性能高效,指是儘可能少地佔用系統資源,包括內存和執行時間。
(7)可移植性,指爲了在原來設計的特定環境之外運行,對系統進行修改的能力。

對外接口原則

【原則4.1.2】對於主要功能模塊抽象模塊接口,通過interface提供對外功能。

值與指針(T/*T)的使用原則

【建議4.1.3.1】基本類型傳遞時,儘量使用值傳遞。

【建議4.1.3.2】如果傳遞字符串或者接口對象時,建議直接實例傳遞而不是指針傳遞。

【建議4.1.3.3】如果是map、func、chan,那麼直接用T。

【建議4.1.3.4】如果是slice,method裏面不重新reslice之類的就用T。

【建議4.1.3.5】如果想通過method改變裏面的屬性,那麼請使用*T。

【建議4.1.3.6】如果是struct,並且裏面包含了sync.Mutex之類的同步原語,那麼請使用*T,避免copy。

【建議4.1.3.7】如果是一個大型的struct或者array,那麼使用*T會比較輕量,效率更高。

【建議4.1.3.8】如果是struct、slice、array裏面的元素是一個指針類型,然後調用函數又會改變這個數據,那麼對於讀者來說採用*T比較容易懂。

【建議4.1.3.9】其它情況下,建議採用*T。

init的使用原則

【規則4.1.4.1】一個文件只定義一個init函數。

【規則4.1.4.2】一個包內的如果存在多個init函數,不能有任何的依賴關係。

defer的使用原則

【建議4.1.5.1】如果函數存在多個返回的地方,則採用defer來完成如關閉資源、解鎖等清理操作。

【建議4.1.5.2】defer會消耗更多的系統資源,不建議用於頻繁調用的方法中。

【建議4.1.5.3】避免在for循環中使用defer。

Goroutine使用原則

【規則4.1.6.1】確保每個goroutine都能退出。

【規則4.1.6.2】禁止在閉包中直接引用閉包外部的循環變量。

Channel使用原則

【規則4.1.7.1】傳遞channel類型的參數時應該區分其職責。

【規則4.1.7.2】確保對channel是否關閉做檢查。

【規則4.1.7.3】禁止重複釋放channel。

其它

【建議4.1.8.1】使用go vet --shadow檢查變量覆蓋,以避免無意的變量覆蓋。

【建議4.1.8.2】GO的結構體中控制使用Slice和Map。

【規則4.1.8.3】避免在循環引用調用 runtime.SetFinalizer。

【規則4.1.8.4】避免在for循環中使用time.Tick()函數。

性能效率

Memory優化

【建議4.2.1.1】將多次分配小對象組合爲一次分配大對象。

【建議4.2.1.2】將多個不同的小對象綁成一個大結構,可以減少內存分配的次數。

【建議4.2.1.3】組合內存分配的一個特殊情形是對分片數組進行預分配。

【建議4.2.1.4】儘可能使用小數據類型,並儘可能滿足硬件流水線(Pipeline)的操作,如對齊數據預取邊界。

【建議4.2.1.5】使用對象池來重用臨時對象,減少內存分配。

GC 優化

【建議4.2.2.1】設置GOMAXPROCS爲CPU的核心數目,或者稍高的數值。

【建議4.2.2.2】避免頻繁創建對象導致GC處理性能問題。

其它優化建議

【建議4.2.3.1】減少[]byte和string之間的轉換,儘量使用[]byte來處理字符。

【建議4.2.3.2】make申請slice/map時,根據預估大小來申請合適內存。

【建議4.2.3.3】字符串拼接優先考慮bytes.Buffer。

【建議4.2.3.4】避免使用CGO或者減少跨CGO調用次數。

【建議4.2.3.5】避免高併發調用同步系統接口。

【建議4.2.3.6】高併發時避免共享對象互斥。

【建議4.2.3.7】長調用鏈或在函數中避免申明較多較大臨時變量。

【建議4.2.3.8】爲高併發的輕量級任務處理創建routine池。

【建議4.2.3.9】建議版本提供性能/內存監控的功能,並動態開啓關閉,但不要長期開啓pprof提供的CPU與MEM profile功能。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章