送給學Go或者轉Go同學的一套編碼規范

有沒有 xdm 是從別的語言轉 Go 的,比如 Java 、php 等,有兄弟在剛開始學的時候疑惑怎么能寫出來優秀的代碼。最近在項目中也 codereview 了不少 Go 語言的代碼,有必要總結下代碼規范,算是一個筆記記錄了。

說在前面,這只是我們團隊的一套規范而已。

今天我們聊一下 Go 的編碼規范,大概分為幾大模塊,如注包/變量/常量命名、基本語法、函數、錯誤處理、心得等。

1. 代碼風格

1.1 代碼格式

  • 代碼必須用 gofmt 進行格式化,goland 可以配置,可以自行搜索一下配置
  • 我們編寫的代碼每行應該不超過 120 個字符,超出部分用換行解決。
  • 單個文件最大行數最大不超過 800 行.
  • 單個函數最大行數不超過 80 行。
  • import 規范
    • 不要使用相對路徑引入包,例如 import ../util/net
    • 在導入包時,多個相同包名沖突時,必須使用導入別名
// bad
"github.com/google/uuid"

// good
uuid "github.com/google/uuid"
  • 導入的包建議分組,引用匿名包建議用一個新的分組,并加上注釋方便后面小伙伴閱讀
import (
    // Go 標準庫
    "fmt"

    //第三方包
    "github.com/jinzhu/gorm"
    "github.com/google/uuid"
    "github.com/go-redis/redis/v8"

    // 匿名包
    /import mysql driver
    _"github.com/jinzhu/gorm/dialects/mysql"

    // 內部包
    slice "xxx.local/pkg/v1/goslice"
    meta "xxx.local/pkg/v1/meta"
    gomap "xxx.local/pkg/v2/gomap"
)

1.2 聲明、初始化和定義

  • 一個函數需要使用多個變量時,可以在函數最開頭處使用 var 聲明。在函數外部聲明的變量不能使用 :=,會踩坑,不知道的可以評論區留言(要評論不易呀)!
var (
    port = 8081
    metricServerPort = 2001
)
  • 在初始化結構體用 &struct 代替 new(struct),確保與結構體初始化一致,初始化結構體時換行。
// bad
stu := new(S)
stu.Name = "張三"

// good
stu := &S{
    Name:"李四"
}
  • 使用 make 在聲明 map、array 等應該指定容器的容量,從而達到預先分配內容。
users := make(map[int]string, 10)

tags := make([]int, 0, 10)
  • 使用標準 var 關鍵字事,不要指定類型,除非它與表達式的類型不同。
// bad
var _f string F()

func F() string {
    return "hello world!"
}

// good 
var _f F()

func F() string {
    return "hello world!"
}

1.3 error 處理

  • 若函數返回 error, 必須對 error 進行處理,如果業務允許可以用 _ 接受忽略。對應 defer 可以不用顯式進行處理。
// bad
func InitConfig() error {
    ...
}
InitConfig()


// good
func InitConfig() error {
    ...
}
err := InitConfig()
if err != nil {
    ...
}
// or 
_ := InitConfig() 
  • error 作為返回值時必須作為最后一個參數返回
// bad
func InitConfig() (error,int) {
    ...
}

// good 
func InitConfig() (int, error) {
    ...
}
  • 錯誤需要單獨處理,盡量不要與其他的邏輯耦合在一起。
// bad
res, err := InitConfig()
if err != nil || res != nil {
    return err
}

// good
res, err := InitConfig()
if err != nil {
    return err
}
if res != nil {
    return fmt.Errorf("invalid result")
}

1.4 panic處理

  • 業務代碼中禁止拋出 panic 錯誤。
  • panic 只允許出現在在服務啟動之前,如讀取配置、鏈接存儲(redis、mysql 等)。
  • 業務代碼中建議用 error 而不是 panic 來傳遞。

1.5 單元測試

  • 每個重要的函數都要編寫測試用例,合并代碼要自動化運行一下所有的 test。
  • 文件命名 xxx_test.go。
  • 函數命名建議使用 Test函數名。

2. 命名規范

在每個語言中,命名規范在代碼規范中非常重要,一個統一的、精確的命名不僅僅可以提高代碼的可讀性,也可以讓人覺的這個同志真的會呀。牛!

2.1 包命名規范

  • 包名必須與目錄名一致(這和其他 php、Java 還是有一點不太一樣的),盡量采取有意義、簡短的包名,不要與 go 的標準庫名稱一樣。
  • 包名小寫,沒有下劃線,可以使用中劃線隔開,使用多級目錄來劃分目錄。
  • 包名不要出現復數命名。
  • 包名命名盡量簡單一目了然,ge:user、log。

2.2 文件命名規范

  • 文件名要見名思義,盡量簡而短
  • 文件名小寫,組合詞用下劃線分割

2.3 函數命名規范

  • 與 php、Java 一樣,必須遵循駝峰規范,Go 語言中需要根據訪問的控制決定大駝峰還是小駝峰。
  • 單元測試的函數用大駝峰,TestFunc。

2.4 結構體命名規范

  • 與 php、Java 一樣,必須遵循駝峰規范,Go 語言中需要根據訪問的控制決定大駝峰還是小駝峰。
  • 避免使用 info 、data 這種無意義的名稱。
  • 命名使用名詞而非動詞。
  • 結構體在聲明和初始化的時候需要換行,eg:
type Student struct{
    Name string
    Age uint8
}

student := Student{
    Name: "張三",
    Age: 18,
}

2.5 變量命名規范

  • 和 php、Java 一樣,必須遵循駝峰規范,Go 語言中需要根據訪問的控制決定大駝峰還是小駝峰。
  • 若變量為私有時,可以使用小寫命名。
  • 局部變量可以簡寫,eg:i 表示 index。
  • 若變量代表 bool 值,則可以使用 Is 、Can、Has 前綴命名,eg:
var isExit bool
var canReturn bool

2.6 常量命名規范

  • 必須遵循駝峰規范,Go 語言中需要根據訪問的控制決定大駝峰還是小駝峰。
  • 若代表枚舉值,需要先創建。
type Code int

const (
    ErrNotFound Code = iota
    ErrFatal
)

3. 類型

3.1 字符串

好像學過的語言中,都是從字符串開始說起的。就像寫代碼第一行都是從 Hello World!一樣!同意的點贊哈。

  • 字符串判空值
// bad
if s == "" {
    ...
}

// good
if len(s) == 0 {
    ...
}
  • 字符串去除前后子串。
// bad
var s1 "hello world"
var s2 "hello"
var s3 strings.TrimPrefix(s1, s2)

// good
var s1 "hello world"
var s2 "hello"
var s3 string

if strings.HasPrefix(s1, s2){
    s3 = s1[len(s2):]
}

3.2 切片 slice

  • 聲明 slice。
// bad
s := []string{}
s := make([]string, 10)

// good
var s []string
s := make([]string, 0, 10)
  • 非空判斷。
//bad
if len(slice) >0 {
    ...
}

// good
if slice != nil && len(slice) > 0 {
    ...
}
  • slice copy。
// bad
var b1,b2 []byte
for i, v := range b1 {
    b2[i] = v
}
for i := range b1 {
    b2[i] = b1[i]
}

// good
copy(b2,b1)
  • slice 新增。
// bad
var a,b []int
for _, v := range a {
    b = append(b,v)
}

// good
var a, b []int
b := append(b, a...)

3.4 結構體 struct

  • 初始化需要多行。
type Student struct{
    Name string
    Age uint8
}

student := Student{
    Name: "張三",
    Age: 18,
}

4. 控制語句

4.1 if

  • if 可以用局部變量的方式初始化。
if err := InitConfig; err != nil {
    return err
}

4.2 for

  • 不允許在 for 中使用 defer, defer 只在函數結束時才會執行。
// bad
for file := range files {
    fd, err := os.Open(file)
    if err != nil {
        return err
    }
    defer fd.close()
    
}

// good
for file := range files{
    func() {
        fd,err := os.open(file)
        if err!=nil {
            return err
        }
        defer fd.close()
    }()
}

4.3 range

  • 如果不需要 key 直接用 _ 忽略,value 也一樣。
for _, v := range students {
    ...
}

for i, _ := range students {
    ...
}

for i, v := range students {
    ...
}

注: 若操作指針時請注意不能直接用 s := v。想知道可以評論區告訴我哦!

4.4 switch

  • 和其他語言不一樣,必須要有 defalt
switch type {
    case 1:
        fmt.Println("type = 1")
        break
     case 2:
        fmt.Println("type = 2")
        break
     default :
        fmt.Println("unKnown type")
}

4.5 goto

  • 業務中不允許使用 goto。
  • 框架和公共工具也不允許使用 goto。

5. 函數

  • 傳參和返回的變量小寫字母。
  • 傳入參數時slice、map、interface、chan 禁止傳遞指針類型。
  • 采用值傳遞,不用指針傳值。
  • 入參個數不能超出 5 個,超過的可以用 struct 傳值。

5.1 函數參數

  • 返回值超出 1 個時,需要用變量名返回。
  • 多個返回值可以用 struct 傳。

5.2 defer

  • 當操作資源、或者事物需要提交回滾時,可以在創建開始下方就使用 defer 釋放資源。
  • 創建資源后判斷 error,非 error 情況后在用 defer 釋放。

5.3 代碼嵌套

  • 為了代碼可讀性,為了世界和平,盡量別用太多的嵌套,因為真的很難有人類能看懂。

6. 日常使用感悟

  • 能不用全局變量就不用,可以用參數傳值的方式,這樣可以大大降低耦合,更有利于單元測試。
  • 衣服開發中,在函數間多用 context 傳遞上下文,在請求開始時可以生成一個 request_id,便于鏈路、日志追蹤。

6.1 提高性能

  • 在業務開發中,盡量使用 strconv 來替代 fmt。
  • 我們在使用 string 字符串類型時,當修改的場景較多,盡量在使用時用 []byte 來替代。因為每次對 string 的修改都需要重新在申請內存。

6.2 避免踩坑

  • append 要小心自動擴容的情況,最好在申明時分配好容量,避免擴容所帶來的性能上的損耗以及分配新的內存地址。若不能確定容量,應選擇一個比較大一點的值。
  • 并發場景下,map 非線程安全,需要加鎖。還有一種評論區告訴我吧。
  • interface 在編譯期間無法被檢查,使用上會出現 panic,需要注意

7. 總結

本篇很講了 Go 語言的編碼規范,當時想說的,規范是大家預定的東西,每個公司、團隊都會有不一樣的規范,只要大家一起遵循就好啦。你可以根據自己團隊的需求,定一套屬于自己團隊的項目規范。如果想小伙伴一起遵循,可以借助一些工具來保障執行度。

講了很多,雖然很基礎,希望對于剛剛轉 Go 語言,或者剛學習 Go 語言的同學有幫助吧。今天就到這里了。希望得到大家的一鍵三連。感謝!

歡迎點贊關注,公眾號搜:程序員祝融

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,556評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,463評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,778評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,218評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,436評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,969評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,795評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,993評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,229評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,687評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,990評論 2 374

推薦閱讀更多精彩內容

  • 這份規范,是參考了 Go 官方提供的編碼規范,以及 Go 社區沉淀的一些比較合理的規范之后,加入自己的理解總結出的...
    拾丨玖閱讀 1,286評論 0 4
  • Uber Go 語言編碼規范 Uber 是一家美國硅谷的科技公司,也是 Go 語言的早期 adopter。其開源了...
    知識鋪閱讀 534評論 0 0
  • 本規范旨在為日常Go項目開發提供一個代碼的規范指導,方便團隊形成一個統一的代碼風格,提高代碼的可讀性,規范性和統一...
    Shaw_Lee閱讀 1,115評論 0 1
  • 內容列表 指導原則指向interface的指針接收器(receiver)與接口零值Mutex是有效的在邊界處拷貝S...
    金科_閱讀 1,065評論 0 0
  • 引言 Go 語言是從既有的語言中借鑒了許多理念,但其與眾不同的特性, 使得使用 Go 編程在本質上就不同于其它語言...
    望仔閱讀 570評論 0 0