gofmt
大部分的格式問題可以通過gofmt解決,gofmt自動格式化代碼,保證所有的go代碼一緻的格式。
正常情況下,采用Sublime編寫go代碼時,插件GoSublilme已經調用gofmt對代碼實作了格式化。
注釋
在編碼階段同步寫好變量、函數、包注釋,注釋可以通過godoc導出生成文檔。
注釋必須是完整的句子,以需要注釋的内容作為開頭,句點作為結尾。
程式中每一個被導出的(大寫的)名字,都應該有一個文檔注釋。
- 包注釋
每個程式包都應該有一個包注釋,一個位于package子句之前的塊注釋或行注釋。
包如果有多個go檔案,隻需要出現在一個go檔案中即可。
//Package regexp implements a simple library
//for regular expressions.
package regexp
- 可導出類型
第一條語句應該為一條概括語句,并且使用被聲明的名字作為開頭。
// Compile parses a regular expression and returns, if successful, a Regexp
// object that can be used to match against text.
func Compile(str string) (regexp *Regexp, err error) {
命名
使用短命名,長名字并不會自動使得事物更易讀,文檔注釋會比格外長的名字更有用。
- 包名
包名應該為小寫單詞,不要使用下劃線或者混合大小寫。
- 接口名
單個函數的接口名以"er"作為字尾,如Reader,Writer
接口的實作則去掉“er”
type Reader interface {
Read(p []byte) (n int, err error)
}
兩個函數的接口名綜合兩個函數名
type WriteFlusher interface {
Write([]byte) (int, error)
Flush() error
}
三個以上函數的接口名,類似于結構體名
type Car interface {
Start([]byte)
Stop() error
Recover()
}
- 混合大小寫
采用駝峰式命名
MixedCaps 大寫開頭,可導出
mixedCaps 小寫開頭,不可導出
- 變量
全局變量:駝峰式,結合是否可導出确定首字母大小寫 參數傳遞:駝峰式,小寫字母開頭 局部變量:下劃線形式
控制結構
- if
if接受初始化語句,約定如下方式建立局部變量
if err := file.Chmod(0664); err != nil {
return err
}
- for
采用短聲明建立局部變量
sum := 0
for i := 0; i < 10; i++ {
sum += i
}
- range
如果隻需要第一項(key),就丢棄第二個:
for key := range m {
if key.expired() {
delete(m, key)
}
}
如果隻需要第二項,則把第一項置為下劃線
sum := 0
for _, value := range array {
sum += value
}
- return
盡早return:一旦有錯誤發生,馬上傳回
f, err := os.Open(name)
if err != nil {
return err
}
d, err := f.Stat()
if err != nil {
f.Close()
return err
}
codeUsing(f, d)
函數(必須)
- 函數采用命名的多值傳回
- 傳入變量和傳回變量以小寫字母開頭
在godoc生成的文檔中,帶有傳回值的函數聲明更利于了解func nextInt(b []byte, pos int) (value, nextPos int) {
錯誤處理
- error作為函數的值傳回,必須對error進行處理
- 錯誤描述如果是英文必須為小寫,不需要标點結尾
- 采用獨立的錯誤流進行處理
不要采用這種方式
if err != nil {
// error handling
} else {
// normal code
}
而要采用下面的方式
if err != nil {
// error handling
return // or continue, etc.
}
// normal code
如果傳回值需要初始化,則采用下面的方式
x, err := f()
if err != nil {
// error handling
return
}
// use x
panic
- 盡量不要使用panic,除非你知道你在做什麼
import
- 對import的包進行分組管理,而且标準庫作為第一組
package main import ( "fmt" "hash/adler32" "os" "appengine/user" "appengine/foo" "code.google.com/p/x/y" "github.com/foo/bar" )
goimports實作了自動格式化
縮寫
- 采用全部大寫或者全部小寫來表示縮寫單詞
比如對于url這個單詞,不要使用
UrlPony
而要使用
urlPony 或者 URLPony
參數傳遞
- 對于少量資料,不要傳遞指針
- 對于大量資料的struct可以考慮使用指針
- 傳入參數是map,slice,chan不要傳遞指針
因為map,slice,chan是引用類型,不需要傳遞指針的指針
接受者
- 名稱
統一采用單字母'p'而不是this,me或者self
type T struct{}
func (p *T)Get(){}
- 類型
對于go初學者,接受者的類型如果不清楚,統一采用指針型
func (p *T)Get(){}
而不是
func (p T)Get(){}
在某些情況下,出于性能的考慮,或者類型本來就是引用類型,有一些特例
- 如果接收者是map,slice或者chan,不要用指針傳遞
//Map
package main
import (
"fmt"
)
type mp map[string]string
func (m mp) Set(k, v string) {
m[k] = v
}
func main() {
m := make(mp)
m.Set("k", "v")
fmt.Println(m)
}
//Channel
package main
import (
"fmt"
)
type ch chan interface{}
func (c ch) Push(i interface{}) {
c <- i
}
func (c ch) Pop() interface{} {
return <-c
}
func main() {
c := make(ch, 1)
c.Push("i")
fmt.Println(c.Pop())
}