This is a creation in Article, where the information may have evolved or changed.
Golang Code Specification
Reference https://golang.org/doc/effective_go.html
Project directory Structure specification
packpack.sh 自动打包的脚本,生成类似xxxx.20170713_14:45:35.tar.gz的文件,放在pack文件下└── src 该项目的源代码 ├── main 项目主函数 ├── model 项目代码 ├── research 在实现该项目中探究的一些程序 └── vendor 存放go的库 ├── github.com/xxx 第三方库 └── xxx.com/obc 公司内部的公共库
The directory structure of the project is as concise and clear as possible
File name naming specification
In lowercase, as far as possible to see the name of meaning, see the file name can know the approximate content of the document, for the source code files, file name to represent a module implementation of the function.
Naming conventions
Package Name
Package name in lowercase, use short name, try not to conflict with standard library
Interface Name
The interface name of a single function is suffixed with "er", such as Reader,writer
The implementation of the interface removes the "ER"
interface { Read(p []byteint, err error)}
Two functions Interface name synthesis two function names
interface { Write([]byte) (int, error) Flush() error}
Interface names of more than three functions, similar to struct names
interface { Start([]byte) error Recover()}
Variable
Global variables: Using the Hump naming method, only the global variables within the package, the outer reference needs to write the interface, provide the call local variables: Camel, lowercase letter Start
Constant
Constant: Uppercase with underscore
Import specification
Import in the case of multiple lines, Goimports will automatically help you format, in a file to introduce a package, it is recommended to use the following format:
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" "git.obc.im/obc/utils" "git.obc.im/dep/beego" "git.obc.im/dep/mysql")
Do not use relative paths to introduce packages in your project:
It's not good to import
import “../net”
That's the right thing to do.
import “xxxx.com/proj/net”
Name of function
Function name using hump naming method, try not to use underline
Error handling
Error is returned as the value of the function, and error must be processed as soon as possible
Processing with a separate error stream
Do not use this method
ifnil { // error handling else { // normal code }
Instead, use the following method
ifnil { // error handling return// or continue, etc. } // normal code
If the return value needs to be initialized, use the following method
x, err := f()ifnil { // error handling return}// use x
Panic
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 recommended that you use log in the main package. Fatal to log errors so that the program can be terminated by log.
Recover
Recover is used to capture runtime anomalies, prohibit misuse of recover, and try not to use Recover,recover in the development testing phase where you think there will be unexpected anomalies.
func server(workChan <-chan *Work) { for work := range workChan { go safelyDo(work) }}func safelyDo(work *Work) { defer func() { if err := recover(); err != nil { log.Println("work failed:", err) } }() // do 函数可能会有不可预期的异常 do(work)}
Defer
Defer is performed before the function return, it is good for some resources to be recycled defer, but it is also forbidden to misuse defer,defer to consume performance, so frequently called functions do not use defer as much as possible.
//Contents Returns the file ' s Contents as a string.func Contents(filename string) (string, error) {F, err: = OS. Open (filename)ifErr! = Nil {return "", err} defer F.close ()//F.close'll run when we ' re finished. varresult []byteBUF: = make ([]byte, -) for{N, err: = F.read (buf[0:]) result = Append (result, buf[0: n] ...)//Append is discussed later. ifErr! = Nil {ifErr = = Io. EOF { Break}return ""Err//F'll be closed if we return here.} }return string(result), nil//F'll be closed if we return here.}
Control structure
If
If the initialization statement is accepted, the Convention establishes the local variable as follows
if err := file.Chmod(0664err != nil { return err}
For
Creating local variables with short declarations
0for010; i++ { sum += i}
Range
If you only need the first item (key), discard the second one:
for key := range m { if key.expired() { delete(m, key) }}
If only the second item is required, place the first item as an underscore
0forvalue := range array { value}
Return
Return as soon as possible: Once an error occurs, go back immediately
f, err := os.Open(name)ifnil { return err}d, err := f.Stat()ifnil { f.Close() return err}codeUsing(f, d)
Receiver of the method
The name generally takes the first letter of Strcut and is lowercase, not this,me or self
type T struct{} func (p *T)Get(){}
If the recipient is Map,slice or Chan, do not pass the pointer
//map package main< Span class= "Hljs-title" >import ("FMT") type MP [string ]string func (M MP) set (k, v string ) {M[k] = v} func main () {m: = Make (MP) M.set ( "K" , ) fmt. Println (M)}
//Channelpackage mainimport ( "fmt")type ch chan interfaceinterface{}) { interface{} { return <-c}func main() { 1) c.Push("i") fmt.Println(c.Pop())}
If you need to modify the slice, re-assign the value by returning the value
//Slicepackage mainimport ( "fmt")type slice []bytefunc main() { 0) s = s.addOne(42) byte) []byte { return append(s, b)}
If the recipient contains sync. Mutex or a struct similar to a synchronization field, you must use pointer passing to avoid copying
package mainimport ( "sync")type T struct { lock() { t.m.Lock()}/*Wrong !!!func (t T) lock() { t.m.Lock()}*/func main() { new(T) t.lock()}
If the recipient is a large struct or array, it is more efficient to pass the pointer.
package mainimport ( "FMT" ) type T struct {data [1024 ]byte }func (t *t) Get ( ) byte {return t.data[ 0 ]} func main () {t: = new (t) fmt. Println (T.get ())}