# GO語言代碼規范說明
**《計算機程序設計與解釋》** 中曾經指出“ 代碼必須是本著給人閱讀的原則來編寫,同時順便給計算機執行而已”,這句話簡單精煉的概括出了代碼風格的作用。當你閱讀風格混亂的代碼的時候,你會深深的贊同上面的觀點的。
代碼風格是一個與人有關而計算機無關的問題。代碼風格的好壞,并不會影響計編譯器的編譯執行,但是它確實會影響到團隊工作的協同開發、影響代碼的復用、功能的升級演化、代碼BUG的修復。
每個語言都有屬于自己的代碼規范,在我們學習和使用任何一門編程語言的時候都必須遵循它的代碼規范,只有在遵循代碼規范的基礎進行編碼,才能寫出通用優雅的代碼。
GO語言可能是唯一一個將代碼規范強制統一的語言。其他編譯器完全忽略的問題,在GO語言的編輯器前會被認為是編譯錯誤。因此我們在學習和使用GO語言的時候必須嚴格按照GO語言的代碼規范進行編碼。
GO語言的編碼規范主要分為兩大類,分別是GO編譯器進行的強制編碼規范以及由GO語言推行的非強制性編碼風格建議。
**強制性編碼規范**
GO編譯器強制的編碼規范也是GO語言設計者認為最需要統一的代碼風格,下面我們來加一簡單的說明。
1. 命名
GO語言從語法層面進行了以下限定:任何需要對完暴露的名字必須是大寫字目開頭,不需要對完暴露的則應該以小寫字母開頭。
軟件開發行業最常見的兩種命名方法:駝峰命名法(例如 UserInfo 和 userInfo)和下劃線命名法(例如 user_info),而GO語言明確宣告了用戶駝峰命名法而排斥下劃線命名法。駱駝命名法在Java和C#中得到官方的支持和推薦,而下劃線命名法則主要用在C語言的世界里,比如Linux內核和驅動開發,php則是駝峰法和下劃線命名法都是支持,而且現在有的php框架開始更多的推廣全小寫字母+下劃線命名法。在我們學習和使用GO語言開發的過程還是徹底忘記下劃線命名法吧,避免寫出不倫不類的名字。
2. 排列
GO語言甚至對代碼的排列方式也進行了語法級別的檢查,約定了代碼塊中花括號的明確擺放位置。
Go語言要求“{”必須放在代碼最后一行,不得單獨占一行;同時,else甚至都必須緊跟在之前的右花括號”}“后面并且不能換行。
Go語言的這條規則基本上就保證了所有Go代碼的邏輯結構寫法是完全一致的,也不會再出現有潔癖的程序員在維護別人代碼之前非要把所有花括號的位置都調整一遍的問題。
**非強制性編碼風格建議**
在程序編譯可以的通過的情況下,可以適當調整對代碼進行調整來提升代碼的可讀性。主要內容包括:
* 調整了每條語句的位置
* 重新擺放花括號的位置
* 以制表符縮進代碼
* 添加空格
當然,對于程序編碼風格是可以通過go fmt?工具來完成的。Go語言提供了一個強大的編碼風格調整工具,在程序可以通過編譯后,可以運行:go fmt xxx.go?命令來完成對于源代碼文件xxx.go的編碼風格調整,調整后的代碼就完全符合以上的風格建議,當然,對于命名規則就無法完成調整了,不過源代碼在調整后就更具有可讀性。
# Go語言代碼規范指導
下面根據GO語言的官方規范,整理下相關的規范指導,方便團隊形成統一的代碼風格,提高代碼的可讀性、規范性、統一性。本規范從命名規范、注釋規范、代碼風格、GO語言提供的工具這幾個方面做一個簡單的說明。
## 一、命名規范
命名是代碼規范中非常重要的一部分,統一的命名規范有利于提高代碼的可讀性,好的命名規范,僅僅通過命名就可以獲取足夠多的信息。
Go在命名時以字母a到Z或a到Z或下劃線開頭,后面跟著零或更多的字母、下劃線和數字(0到9)。Go不允許在命名時中使用@、$和%等標點符號。Go是一種區分大小寫的編程語言。因此,Manpower和manpower是兩個不同的命名。
1. 當命名(包括常量、變量、類型、函數名、結構字段等等)以一個大寫字母開頭,如:Group1,那么使用這種形式的標識符的對象就可以被外部包的代碼所使用(客戶端程序需要先導入這個包),這被稱為導出(像面向對象語言中的 public);
2. 命名如果以小寫字母開頭,則對包外是不可見的,但是他們在整個包的內部是可見并且可用的(像面向對象語言中的 private )
### 1、包命名:package
包命名保持和目錄的命名一致,盡量采取簡短、有意義的命名 并且主要盡量不要和標準庫的命名沖突。包名為小寫字母,不要帶下劃線。
```
package demo
package main
```
2、文件名莫名
盡量采取有意義的文件名,簡短,小寫單詞,文件命名是可以是下劃線分隔單詞。
```
my_test.go
```
3、結構體命名
* 采用駝峰命名法,首字母根據訪問控制大小寫
* struct 聲明和初始化格式采用多行
```
//多行聲明
type User struct{
Username string
Email string
}
u :User{
Username:'xiaoming',
Email:'xiaoming@mail.com',
}
```
4、接口命名
* 命名規則基本和上面的結構體類似
* 單個函數的結構名以“er”作為后綴,例如 Reader , Writer.
```
type Reader interface{
Read(p []byte) (n int, err error)
}
```
5、變量命名
* 和結構類似,變量名稱一般遵循駝峰法,首字母根據訪問規則控制大寫或者小寫,但遇到特有名詞時,需要遵循以下原則:
* 如果變量為私有,且特有名詞為首個單詞,則使用小寫 如apiClient
* 其他情況應當使用名詞原有的寫法 如 APIClient 、repoID 、UserId
* 錯誤示例: UrlArray ,應該寫成 urlArray 或者 URLArray
* 如變量類型 bool 類型 ,則名稱以 Has 、Is 、Can 、Allow 開頭
```
var isExist bool
var hasConflict bool
var canMange bool
var allowGitHook bool
```
6、常量命名
常量均使用全部大寫字母,使用下劃線分詞
```
const APP_VERSION = "1.0"
```
如果是枚舉類型的常量,則需要先創建相應的類型
```
type Scheme string
const {
HTTP Scheme = "http"
HTTPS Scheme = "https"
}
```
7、關鍵字
下面列表顯示了GO語言保留的保留單詞,這些保留單詞不能用做常量、變量、其他的標識符名稱
| break | default | func | interface | select | case |
| --- | --- | --- | --- | --- | --- |
| **defer** | **Go** | **map** | **Struct** | **chan** | **else** |
| **Goto** | **package** | **Switch** | **const** | **fallthrough** | **if** |
| **if** | **range** | **Type** | **continue** | **for** | **import** |
| **return** | **Var** | | | | |
## 二、注釋
不管是那種開發語言,在開發過程注釋對于團隊協作開發、后期BUG的修改、功能的優化等等都是特別重要的。
編程語言中的java、php、go、python的注釋風格都跟C語言的注釋風格比較接近。比如 /**/ 這種塊注釋是來自C,// 行注釋是C++的風格。行注釋用的表較多,屬于常態注釋;塊注釋主要為文件注釋或者包注釋,但是在開發過程也是比較常用的,尤其是表達式中很有用或者禁用大量代碼的都會用到塊注釋。
* 單行注釋是最常見的注釋方式,可以在任何地方使用以 //開頭的單行注釋。
* 塊注釋是以 /* 開頭 ,并以 */ 結尾的 不可以嵌套使用,多行注釋一般用于包的文檔注釋或者代碼片段的注釋。
go 語言自帶的 godoc 工具可以根據注釋生成文檔,生成可以自動生成對應的網站(?[http://golang.org](https://link.zhihu.com/?target=http%3A//golang.org)就是使用 godoc 工具直接生成的),注釋的質量決定了生成的文檔的質量。每個包都應該有一個包注釋,在package子句之前有一個塊注釋。對于多文件包,包注釋只需要存在于一個文件中,任何一個都可以。包評論應該介紹包,并提供與整個包相關的信息。它將首先出現在`godoc`頁面上,并應設置下面的詳細文檔。
詳細的如何寫注釋可以 參考:[http://golang.org/doc/effective\_go.html#commentary](https://link.zhihu.com/?target=http%3A//golang.org/doc/effective_go.html%23commentary)
### 1、包注釋
每個包都應該有一個包注釋,一個位于package語句之前的塊注釋或者行注釋,包如果有多個go文件,只需要在其中一個go文件中加注釋即可。包注釋一般按照下面基本信息創建,當然有的公司開發團隊會有自己的注釋風格,如果公司團隊沒有要求,建議使用下面的方式去標注注釋:
* 包的基本簡介(包名、簡介)
* 創建者, 格式:創建人:xx
* 創建時間,格式:創建時間:xxxxx
例如 util 包注釋示例如下
```
/*
utile 包 ,該包包含了項目公用的一些常量,封裝了項目中一些公用函數
創建人:帝君
創建時間:20200522
*/
```
### 2、結構(接口)注釋
每個自定義的結構或者接口都應該有注釋說明,該注釋對結構或者接口進行簡要的介紹,放在結構體定義的前一行,格式為:結構體名、結構體說明。同時結構體內的每個成員變量都要說明,該說明放在成員變量的后面(注意跟變量對齊),實例如下:
```
// User , 用戶對象定義用戶的基礎信息
type User struct{
Username string //用戶名
Email string // 用戶郵箱
}
```
###3、函數(方法)注釋
每個函數或者方法(結構體或者接口下的函數統稱為方法)都應該有注釋說明,函數的注釋應該包括三個方面
* 簡要說明,格式說明:以函數名開頭 “,” 分隔說明部分
* 參數列表,格式說明:每行一個參數 參數名開頭“,” 分隔說明部分
* 返回值:每行一個返回值
示例如下
```
// NewtAttrModel , 屬性數據層操作類的工廠方法
//參數
ctx , 上下文信息
// 返回值:
屬性操作指針
func NewAttrModel(ctx *common.Content) *AttrModel{
}
```
### 4、代碼邏輯注釋
對于一些關鍵位置的代碼邏輯,或者一些邏輯比較復雜的邏輯,需要相應的邏輯說明,方便其他開發這閱讀該段代碼示例如下:
```
// 從 redis 讀取數據,沒有讀取的 ID 沒記錄到一個數組里面,準備從數據庫中讀取
xxxxxxxx
xxxxxxxx
xxxxxxxx
```
###5、注釋風格
統一使用中文注釋,對于中英文之間嚴格使用空格分隔,這個不僅僅是中文和英文之間,英文和中文之間標點也都要使用空格分隔,例如
```
// 從 redis 讀取數據,沒有讀取的 ID 沒記錄到一個數組里面,準備從數據庫中讀取
```
## 三、代碼風格
### 1、縮進和折行
* 縮進直接使用 gofmt 工具格式化即可(gofmt 是使用 tab 縮進的);
* 折行方面,一行最長不超過120個字符,超過的請使用換行展示,盡量保持格式優雅。
我們使用Goland開發工具,可以直接使用快捷鍵:ctrl+alt+L,即可。
### 2、語句的結尾
Go語言中是不需要類似于Java需要冒號結尾,默認一行就是一條數據
如果你打算將多個語句寫在同一行,它們則必須使用?;
### 3、括號和空格
括號和空格方面,也可以直接使用 gofmt 工具格式化(go 會強制左大括號不換行,換行會報語法錯誤),所有的運算符和操作數之間要留空格。
```
//正確的方式
if a > 0 {
}
//錯誤的方式
if a>0 // a、0、> 之間應該有空格
{ //左大括號不能換行不然會報語法錯誤
}
```
### 4、import 規范
import在多行的情況下,goimports會自動幫你格式化,但是我們這里還是規范一下import的一些規范,如果你在一個文件里面引入了一個package,還是建議采用如下格式:
```
import(
"fmt"
)
```
如果你的包引入了三種類型的包,標準庫包,程序內部包,第三方包,建議采用如下方式進行組織你的包:
```
import(
"encodeing/jsong"
"stryings"
"myproject/models"
"myproject/controller"
"myproject/utils"
"github.com/astaxie/beego"
"github.com/go-sql-deiver/mysql"
)
```
有順序的引入包,不同的類型采用空格分離,第一種實標準庫,第二是項目包,第三是第三方包。
在項目中不要使用相對路徑引入包:
//錯誤的包導入
```
import "../net"
//正確的導入
import "github.com/repo/proj/src/net"
```
但是如果是引入本項目中的其他包,最好使用相對路徑。
### 5、錯誤處理
* 錯誤處理的原則就是不能丟棄任何有返回err的調用,不要使用 \_ 丟棄,必須全部處理。接收到錯誤,要么返回err,或者使用log記錄下來
* 盡早return:一旦有錯誤發生,馬上返回
* 盡量不要使用panic,除非你知道你在做什么
* 錯誤描述如果是英文必須為小寫,不需要標點結尾
* 采用獨立的錯誤流進行處理
```
//錯誤的寫法
if err != nil {
//error handliing
} else {
// normal code
}
//正確的寫法
if err != nil {
// error handliing
return //or continue ,etc
}
//normal code
```