This is a creation in Article, where the information may have evolved or changed.
Turn from
Preface
Read many aspects of coding specifications, probably each company has different specifications, this code is written to my own, but also hope that our internal colleagues can follow this specification to write go code.
If your code has no way to find the following specifications, then follow the standard library specifications, read more standard library source code, the standard library is a reference to our code can be said to be the benchmark.
Formatting specifications
The go default already has gofmt
tools, but we strongly recommend using the Goimport tool, which adds automatic deletion and ingestion of packages based on GOFMT.
go get golang.org/x/tools/cmd/goimports
Different editors have different configurations, sublime configuration tutorial: http://michaelwhatcott.com/gosublime-goimports/
Liteide default already supports Goimports, if you do not support click on the property configuration->golangfmt-> tick Goimports
Save your code before automatically fmt.
President's appointment
A line with a maximum of 80 characters, more than the use of line display, try to keep the format elegant.
go vet
Vet tools can help us to static analysis of our source of various problems, such as redundant code, the logic of early return, the struct's tag compliance standards and so on.
go get golang.org/x/tools/cmd/vet
Use the following:
go vet .
Package Name
Keep the package's name and directory consistent, try to take meaningful packages, short, meaningful, and avoid conflicts with standard libraries.
Import specification
Import in the case of multiple lines, Goimports will automatically help you format, but we still regulate the import of some specifications, if you introduce a package in a file, or the following format is recommended:
import "fmt"
If your package introduces three types of packages, standard library packages, program internals, and third-party packages, it is recommended that you organize your packages in the following ways:
import ( "encoding/json" "strings" "myproject/models" "myproject/controller" "myproject/utils" "github.com/astaxie/beego" "github.com/go-sql-driver/mysql")
There are sequential introduction packages, different types are separated by spaces, the first real standard library, the second is the project package, and the third is the third party package.
Do not use relative paths to introduce packages in your project:
// 这是不好的导入import "../net"// 这是正确的做法import "github.com/repo/proj/src/net"
Variable declaration
The variable name uses the hump standard, do not use _ to name the variable name, multiple variable declarations put together
var ( Found bool count int)
Outside of the function declaration must use VAR, do not adopt: =, easy to step on the scope of the variable.
String looping issues for custom types
If a custom type defines a string method, some hidden bugs are generated when printing
type MyInt intfunc (m MyInt) String() string { return fmt.Sprint(m)//BUG:死循环} func(m MyInt) String() string { return fmt.Sprint(int(m)) //这是安全的,因为我们内部进行了类型转换}
Avoid returning named arguments
If your function is short, less than 10 lines of code, then you can use it, otherwise please use the type directly, because if you use a named variable it is easy to cause a hidden bug
func Foo(a int, b int) (string, ok){}
Of course, if more than one parameter of the same type is returned, the named parameter may be clearer:
func (f *Foo) Location() (float64, float64, error)
The following code is clearer:
// Location returns f's latitude and longitude.// Negative values mean south and west, respectively.func (f *Foo) Location() (lat, long float64, err error)
Error handling
The principle of error handling is that you cannot discard any calls that return err, do not use _ discard, and must be handled all. Receive an error, either return err, or panic, or log it using log
Error message
Error information do not use uppercase letters, try to keep your mistakes short, but enough to express the meaning of your mistakes.
Long sentences to print or call, use parameters to format a branch
We are calling FMT. Sprint
or log. Sprint
Functions, we sometimes encounter very long sentences, and we need to split the multiple lines at the parameter call:
The following is the wrong way:
log.Printf(“A long format string: %s %d %d %s”, myStringParameter, len(a), expected.Size, defrobnicate(“Anotherlongstringparameter”, expected.Growth.Nanoseconds() /1e6))
Should be the following way:
log.Printf( “A long format string: %s %d %d %s”, myStringParameter, len(a), expected.Size, defrobnicate( “Anotherlongstringparameter”, expected.Growth.Nanoseconds()/1e6, ),)
Notice the closure of the call
Call a function or Goroutine method in a loop, be sure to use the variable call shown, and do not call the loop parameter inside the closure function.
fori:=0;i<limit;i++{ go func(){ DoSomething(i) }() //错误的做法 go func(i int){ DoSomething(i) }(i)//正确的做法}
Race on loop counter
Disabling panic in logical processing
In the main package only if it is not possible to run the case of panic, such as the file can not be opened, the database can not be connected to cause the program does not work properly, but for the other package external interface can not be panic, can only be used within the packet.
It is strongly recommended that you use log in the main package. Fatal to log errors so that the program can be terminated by log.
Annotation specification
Comments can help us to complete the work of the document well, well-written comments can facilitate our future maintenance. Detailed how to write comments can be consulted: commentary
Bug Notes
For bugs that appear in the code, you can use special annotations in the following tutorials, where godocs can be used to highlight annotations:
// BUG(astaxie):This divides by zero. var i float = 1/0
struct specification
The struct declaration and initialization format takes multiple lines:
Defined as follows:
type User struct{ Username string Email string}
Initialize as follows:
u := User{ Username: "astaxie", Email: "astaxie@gmail.com",}
Recieved is a value type or a pointer type
Whether to use a value type or a pointer type mainly refer to the following principles:
func(w Win) Tally(playerPlayer)int //w不会有任何改变 func(w *Win) Tally(playerPlayer)int //w会改变数据
For more information, please refer to: Codereviewcomments/receiver_type
A struct with a mutex must be a pointer receivers
If you define a struct with a mutex, then your receivers must be a pointer
Resources
Code Review comments
Effective Go