Recently, I have codereviewed a lot of Go language code in the project. It is necessary to summarize the code specifications, which can be regarded as a note record.
As mentioned earlier, this is just a set of norms for our team.
Today we talk about Go’s coding standards, which are roughly divided into several major modules, such as package injection/variable/constant naming, basic syntax, functions, error handling, experience, etc. [Recommended: golang tutorial]
1. Code style
1.1 Code format
- The code must be formatted with gofmt, goland can Configuration, you can search for the configuration by yourself
- Each line of the code we write should not exceed 120 characters, and the excess part should be solved by line breaks.
- The maximum number of lines in a single file does not exceed 800 lines.
- The maximum number of lines in a single function does not exceed 80 lines.
- Import specifications
- Do not use relative paths to introduce packages, for example
import ../util/net
- When importing packages, multiple identical packages When there is a name conflict, you must use the imported alias
// bad
"github.com/google/uuid"
// good
uuid "github.com/google/uuid"
- . The imported package is recommended to be grouped. It is recommended to use a new group when referencing the anonymous package, and add comments for convenience. Partner Reading
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 Declaration, Initialization and Definition
- When a function needs to use multiple variables, you can use the var declaration at the beginning of the function. Variables declared outside the function cannot use :=, which may lead to pitfalls. If you don’t know, you can leave a message in the comment area (it’s not easy to comment)!
var (
port = 8081
metricServerPort = 2001)
- Use &struct instead of new(struct) when initializing the structure to ensure that it is consistent with the initialization of the structure and wrap the line when initializing the structure.
// bad
stu := new(S)
stu.Name = "张三"
// good
stu := &S{
Name:"李四"
}
- Using make, you should specify the capacity of the container when declaring map, array, etc., so as to pre-allocate the content.
users := make(map[int]string, 10)tags := make([]int, 0, 10)
- Use the standard var keyword thing and do not specify a type unless it is different from the type of the expression.
// bad
var _f string F()
func F() string {
return "hello world!"
}
// good
var _f F()
func F() string {
return "hello world!"
}
1.3 Error processing
- If the function returns an error, the error must be processed. If the business allows, you can use _ to accept and ignore it. Corresponding defer can be processed without explicit processing.
// bad
func InitConfig() error {
...
}
InitConfig()
// good
func InitConfig() error {
...
}
err := InitConfig()
if err != nil {
...
}
// or
_ := InitConfig()
- error must be returned as the last parameter when used as a return value
// bad
func InitConfig() (error,int) {
...
}
// good
func InitConfig() (int, error) {
...
}
- Errors need to be handled separately and try not to be coupled with other logic. Together.
// 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 handling
- It is forbidden to throw panic errors in business code.
- panic is only allowed to appear before the service is started, such as reading configuration, link storage (redis, mysql, etc.).
- It is recommended to use error instead of panic in business code.
1.5 Unit Test
- A test case must be written for each important function, and all tests must be automatically run when merging the code.
- The file is named xxx_test.go.
- It is recommended to use the Test function name for function naming.
2. Naming convention
In every language, naming convention is very important in code specification. A unified and accurate naming can not only Improving the readability of the code can also make people feel that this comrade really knows how to do it. ox!
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 boolvar canReturn bool
2.6 常量命名规范
- 必须遵循驼峰规范,Go 语言中需要根据访问的控制决定大驼峰还是小驼峰。
- 若代表枚举值,需要先创建。
type Code intconst (
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 stringif strings.HasPrefix(s1, s2){
s3 = s1[len(s2):]}
3.2 切片 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 {
...}
// badvar b1,b2 []bytefor i, v := range b1 {
b2[i] = v}for i := range b1 {
b2[i] = b1[i]}// goodcopy(b2,b1)
// bad
var a,b []intfor _, 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 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
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 语言的同学有帮助吧。今天就到这里了。希望得到大家的一键三连。感谢!
本文系转载,原文链接:mp.weixin.qq.com/s/lfjP9DEia2WL4Ua...
The above is the detailed content of Share a set of Go coding standards! Welcome to collect!. For more information, please follow other related articles on the PHP Chinese website!