Appearance
The Go Programming Language - 编码规范
1. 命名规范
1.1. 文件名称
应为小写单词,可以使用下划线分隔各个单词。
Text
helloworld_test.go1.2. package 名称
- 应该为小写单词,不要使用下划线或混合大小写;
- 尽量和目录保持一致(但不绝对,例如 main 包);
- 尽量不要和 Go 的标准库名冲突;
Go
package demo1.3. 结构体名称
采用驼峰命名法,首字母根据访问控制选择大小写。
Go
type Person struct {
Id int32
UserName string
}1
2
3
4
2
3
4
1.4. 接口名称
- 采用驼峰命名法,首字母根据访问控制选择大小写;
- 单个函数的结构体名称以 “er” 作为后缀,例如:
Reader、Writer;
Go
type Reader interface {
Read(p []byte) (n int, err error)
}1
2
3
2
3
1.5. 变量名称
- 采用驼峰命名法,首字母根据访问控制选择大小写,但遇到特有名词时,需要遵循以下规则:
- 私有变量,特有名词为首个单词时应使用小写,如:
apiClient、urlArray、id - 其它情况,特有名词为应使用该名词原有写法,如:
APIClient、URLArray、Id,错误示例:、ApiClient、UrlArrayID
- 私有变量,特有名词为首个单词时应使用小写,如:
- 若变量类型为
bool类型,则名称应以has、is、can或allow等之类的单词开头;
Go
var isExist bool
var URLArray []string
var updTOCCommand Command // toc: table of content1
2
3
2
3
1.6. 常量名称
- 全部使用大写字母,并使用下划线分词;
- 如果是枚举类型的常量,则应先创建相应类型;
Go
// 普通类型常量
const API_KEY = "0c5d6aa49efe41ddbccf7dcb4cdd3d56"
// 枚举类型常量
type Scheme string
const (
HTTP Scheme = "http"
HTTPS Scheme = "https"
)1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
2. 代码风格
2.1. 可见性
当命名(常量、变量、类型、函数名、结构体字段等)以一个大写字母开头,那么该对象就可以被外部包的代码所使用,这被称为导出(类似 public)。
命名如果以小写字母开头,则对外部包来说是不可见的,但是它们在整个包的内部是可见的(类似 private)。
2.2. 格式化
Go 语言不需要在语句或者声明的末尾添加分号,除非一行上有多条语句。
实际上,编译器会主动把特定符号后的换行符转换为分号(比如行末是标识符、整数、浮点数、虚数、字符、字符串、break、continue、fallthrough、return、运算符、分隔符 ++、--、)、] 或 }),因此换行符添加的位置会影响 Go 代码的正确解析。
举个例子,函数的左括号 { 必须和 func 函数声明在同一行上,且位于末尾,不能独占一行,而在表达式 x + y 中,可在 + 后换行,不能在 + 前换行(以 + 结尾的话不会被插入分号分隔符,但是以 x 结尾的话则会被分号分隔符,从而导致编译错误)。
Go 语言在代码格式上采取了很强硬的态度。gofmt 工具把代码格式化为标准格式,并且这个格式化工具没有任何可以调整代码格式的参数。
2.3. import 规范
如果你的包引入了三种类型的包:标准库包、程序内部包、第三方包,建议采用如下方式进行组织排序:
Go
import (
"encoding/json"
"strings"
"demo/controller"
"demo/models"
"demo/utils"
"github.com/astaxie/beego"
"github.com/go-sql-driver/mysql"
)1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
Note
- 必须恰当导入需要的包,缺少了必要的包或者导入了不需要的包,程序都无法编译通过;
- import 声明必须跟在文件的 package 声明之后;
2.4. 错误处理
尽量不要使用
panic;尽早
return,一旦发生错误,尽早返回error;错误描述如果是英文必须为小写,不要出现换行符,不需要标点结尾;
任何调用返回的
error都不要使用_丢弃,可以选择处理错误、返回错误或者使用log记录;采用独立的错误流进行处理:
Go// 不推荐以下写法: if err != nil { // error handling } else { // continue ... } // 推荐的写法: if err != nil { // error handling return } // continue ...1
2
3
4
5
6
7
8
9
10
11
12
13
2.4.1. 常用的错误处理策略
传播错误
调用函数失败时,我们可以将错误信息以链式组合在一起,因此错误信息中应避免大写、换行符和标点符号结尾,同时我们还会将调用信息和参数信息作为发生错误时的上下文放在错误信息中并返回给调用者,例如:
Godoc, err := html.Parse(resp.Body) resp.Body.Close() if err != nil { return nil, fmt.Errorf("parsing %s as HTML: %v", url, err) }1
2
3
4
5最终的错误信息可能很长,我们可以通过类似
grep的工具处理错误信息(注:grep是一种文本搜索工具)。当错误最终被函数处理时,错误信息应提供清晰的从原因到后果的因果链,就像美国宇航局事故调查时做的那样:Textgenesis: crashed: no parachute: G-switch failed: bad relay orientationText创世纪:坠毁:未打开降落伞:打开 G 开关失败:继电器方向错误重新尝试失败的操作
如果错误的发生是偶然性的,或由不可预知的问题导致的。一个明智的选择是重新尝试失败的操作。在重试时,我们需要限制重试的时间间隔或重试的次数,防止无限制的重试。
输出错误信息并结束程序
如果错误发生后,程序无法继续运行,我们就可以采用第三种策略:输出错误信息并结束程序。需要注意的是,这种策略只应在 main 中执行。对库函数而言,应仅向上传播错误,除非该错误意味着程序内部包含不一致性,即遇到了 bug,才能在库函数中结束程序。
只需要输出错误信息
有时,我们只需要输出错误信息就足够了,不需要中断程序的运行。我们可以使用 log 包中提供的函数:
Goif err := Ping(); err != nil { log.Printf("ping failed: %v; networking disabled", err) }1
2
3
2.5. 单元测试
- 单元测试文件名以 “_test.go” 结尾,例如:
translator_test.go。 - 测试用例的函数名必须以 Test 开头,例如:
func TestTranslate()。