Reference effective_go
Project directory structure specification
PROJECT_NAME ├─ Readme. md Introduction to Software and Documentation ├─ bin Compiled binary, run./build.sh to automatically generate, ├─ build.sh Automatic compiled Script ├─ doc Project document ├─ pack Pack after the program here ├─ pack.sh Automatic packed script Generate a file similar to XXXX.20170713_14:45:35.tar. gz, ├─ SRC project source Code ├─ main Project Main Function ├─ Model project code ├─ research Exercises for implementing the project ├─ vendor store go library ├─ github.com/xxx ├ ── xxx.com/obc An internal public library of the companyCopy the code
The directory structure of the project should be as concise and hierarchical as possible
Naming conventions for file names
Use lowercase, as far as possible to see the name, see the file name can know the general content of the file, for the source code of the file, the file name should be a good representation of a module to achieve the function.
Naming conventions
The package name
Use lowercase package names, short names, and try not to conflict with the standard library
The interface name
The interface names of a single function, such as Reader or Writer, are suffixed with er
The implementation of the interface drops the “er”
type Reader interface {
Read(p []byte) (n int, err error)
}
Copy the code
The interface names of two functions combine two function names
type WriteFlusher interface {
Write([]byte) (int, error)
Flush() error
}
Copy the code
The interface name of more than three functions, similar to the structure name
type Car interface {
Start([]byte)
Stop() error
Recover()
}
Copy the code
variable
Global variables: use the camel name, only in the package of global variables, outside the package reference need to write interface, provide to call local variables: camel, lowercase letter beginning
constant
Constants: uppercase, underlined
The import specification
Import In the case of multiple lines, Goimports automatically formats the package for you. It imports a package in a file.
import (
"fmt"
)
Copy the code
If your package introduces three types of packages: library packages, in-app packages, and third-party packages, it is recommended to organize your package in the following way:
import (
"encoding/json"
"strings"
"myproject/models"
"myproject/controller"
"git.obc.im/obc/utils"
"git.obc.im/dep/beego"
"git.obc.im/dep/mysql"
)
Copy the code
Do not import packages using relative paths in a project:
// This is a bad import
The import ".. / net"Copy the code
// This is the right thing to do
The import "xxxx.com/proj/net"Copy the code
The function name
Function names are camel – humped and do not use underscores
Error handling
The error is returned as the value of the function, so you have to deal with the error as quickly as possible and you have to deal with the error as a separate error stream so don’t do that
iferr ! = nil { // error handling }else {
// normal code
}
Copy the code
Instead, do the following
iferr ! = nil { // error handlingreturn // or continue, etc.
}
// normal code
Copy the code
If the return value needs to be initialized, do as follows
x, err := f()
iferr ! = nil { // error handlingreturn
}
// use x
Copy the code
Panic
To disable panic in logical processing, panic is used in the main package only when it is really impossible to run, such as file cannot be opened and database cannot be connected, so the program cannot run normally. However, panic cannot be used in external interfaces of other packages, and can only be used in packages. It is recommended to use log.fatal in the main package to record errors so that the program can be terminated by log.
Recover
Recover is used to catch runtime exceptions. Misuse of Recover is prohibited. Try not to use Recover during development and testing.
func server(workChan <-chan *Work) {
for work := range workChan {
go safelyDo(work)
}
}
func safelyDo(work *Work) {
defer func() {
iferr := recover(); err ! = nil { log.Println("work failed:", err)
}
}()
// doThe function may have unexpected exceptionsdo(work)
}
Copy the code
Defer
Defer is executed before the function return. It is good to use defer for some resource reclamation, but it is forbidden to abuse it. Defer is a performance drain, so try not to use it for frequently invoked functions.
// Contents returns the file's contents as a string. func Contents(filename string) (string, error) { f, err := os.Open(filename) if err ! = nil { return "", err } defer f.Close() // f.Close will run when we're finished.
var result []byte
buf := make([]byte, 100)
for {
n, err := f.Read(buf[0:])
result = append(result, buf[0:n]...) // append is discussed later.
iferr ! = nil {if err == io.EOF {
break
}
return "", err // f will be closed if we return here.
}
}
return string(result), nil // f will be closed if we return here.
}
Copy the code
Control structure
if
If accepts an initialization statement, and the convention is to create a local variable as follows
iferr := file.Chmod(0664); err ! = nil {return err
}
Copy the code
for
Use short declarations to create local variables
sum := 0
for i := 0; i < 10; i++ {
sum += i
}
Copy the code
range
If only the first item is needed, discard the second:
for key := range m {
if key.expired() {
delete(m, key)
}
}
Copy the code
If only the second term is needed, underline the first term
sum := 0
for _, value := range array {
sum += value
}
Copy the code
return
Return early: If an error occurs, return immediately
f, err := os.Open(name)
iferr ! = nil {return err
}
d, err := f.Stat()
iferr ! = nil { f.Close()return err
}
codeUsing(f, d)
Copy the code
Method receiver
Names are usually the first letter of strcut and lowercase, not this, me, or self
type T struct{}
func (p *T)Get() {}Copy the code
Do not use Pointers if the recipient is map, Slice, or 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)
}
Copy the code
//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())
}
Copy the code
If slice needs to be modified, it is reassigned with a return value
//Slice
package main
import (
"fmt"
)
type slice []byte
func main() {
s := make(slice, 0)
s = s.addOne(42)
fmt.Println(s)
}
func (s slice) addOne(b byte) []byte {
return append(s, b)
}
Copy the code
If the receiver is a structure containing sync.mutex or similar synchronization fields, you must use pointer passing to avoid replication
package main
import (
"sync"
)
type T struct {
m sync.Mutex
}
func (t *T) lock() {
t.m.Lock()
}
/*
Wrong !!!
func (t T) lock() {
t.m.Lock()
}
*/
func main() {
t := new(T)
t.lock()
}
Copy the code
If the receiver is a large structure or array, it is more efficient to use pointer passing.
package main
import (
"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())
}
Copy the code
Note: the transfer: https://sheepbao.github.io/post/golang_code_specification/