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/