Naming rules
- From the caller’s point of view, the package is not for your own use
- Concise, and see the name know meaning
- Use a general, well-known abbreviation named. Such as
buf
Rather thanbufio
- If the abbreviated name is ambiguous, drop it or change it
The file name
The main entry file for the entire application or package should be main.go, or the same as the short name of the application.
For example, the main entry file of the spiker package is spiker.go, and the main entry file of the application is main.go
The package name
-
The package name is the same as the directory name
If multiple packages appear in a directory at the same time, compilation fails:
found packages pkg (a.go) and pb (b.go) in XXX Copy the code
-
In most cases with named imports, renaming is not required
Don’t let callers alias names unless they suck
-
All lowercase, no underscores, no caps. Error examples MyPackage, my_package, MyPackage
-
No complex numbers. For example, net/ URL, not net/urls
-
Don’t use names that aren’t informative. Error examples common, lib, util
Import packages
- If the package name does not match the last element of the import path, the import alias must be used
import (
client "example.com/client-go"
trace "example.com/trace/v2"
)
Copy the code
- In all other cases, import aliases should be avoided unless there is a direct conflict between imports
import (
"net/http/pprof"
gpprof "github.com/google/pprof"
)
Copy the code
-
In case of duplicate names, keep standard packages and alias custom or third party packages
-
In non-test files (*_test.go), disallow the use of. To simplify object calls to import packages
-
Do not use relative path import (./subpackage). All import paths must comply with the Go GET standard
Hump nomenclature
Constants, variables, types, structs, interfaces, functions, methods, properties, etc., all use hump MixedCaps or MixedCaps.
Names starting with an underscore are not allowed, and Go uses case to distinguish between public and private names.
With one exception, function names may contain underscores for grouping related test cases, such as TestMyFunction_WhatIsBeingTested.
Bad:
const ROLE_NAME = 10
Copy the code
Good:
const RoleName = 10
Copy the code
constant
- If it is a constant of enumerated type, you need to create the corresponding type first
type Scheme string
const (
Http Scheme = "http"
Https Scheme = "https"
)
Copy the code
- If the functionality of the module is complex and constant names are confusing, use full prefixes to better distinguish enumerated types
type Symbol string
const (
SymbolAdd Symbol = "+"
SymbolSub Symbol = "-"
)
Copy the code
variable
-
In a relatively simple environment with a small number of targeted objects, you can abbreviate some names from full words to single letters
user
I can write it as thetau
userId
Can be abbreviateduid
-
If the variable type Is bool, the name should start with Has, Is, Can, or Allow
var isExist bool
var hasConflict bool
var canManage bool
var allowGitHook bool
Copy the code
URL
- The URL name is all lowercase
- With a forward slash
/
Show hierarchy - Use a hyphen
-
To improve the readability of names in long paths - Underscores must not be used in urls
_
- Urls should not end with forward slashes
/
- File extensions should not be included in the URL
- The URL must be known by name, but must not reveal the server architecture
Bad:
/GetUserInfo
/photos_path
/My-Folder/my-doc/
/user/user-list
Copy the code
Good:
/user/list
/user/operator-logs
Copy the code
Function/method name
-
Don’t gild the lily
-
Long names do not make them more readable, and a useful documentation is often more valuable than additional long names
Bad:
once.DoOrWaitUntilDone(f)
Copy the code
Good:
once.Do(f)
Copy the code
- A function named New in the PKG package returns a value of type pkg.pkg
q := list.New() // q is a *list.List
Copy the code
- When a function in a PKG package returns a value of type pkg.pkg (or * PKG.pkg), the function name should omit the type name
start := time.Now() // start is a time.Time
t, err := time.Parse(time.Kitchen, "6:06PM") // t is a time.Time
Copy the code
- When a function returns a value of type pkG. T and T is not PKG, the function name should include T to make the user code easier to understand
ticker := time.NewTicker(d) // ticker is a *time.Ticker
timer := time.NewTimer(d) // timer is a *time.Timer
Copy the code
-
Getter/setter
Go does not provide automatic support for getters and setters. For a variable or field, the getter name does not carry Get; the setter name begins with Set.
If you have a field named OWNER (lowercase, unexported), its getter should be owner (uppercase, exportable) instead of GetOwner.
Bad:
owner := obj.GetOwner()
ifowner ! = user { obj.SettingOwner(user) }Copy the code
Good:
owner := obj.Owner()
ifowner ! = user { obj.SetOwner(user) }Copy the code
- If the function or method is of judgment type (the return value is primarily bool), the name should be
Has
,Is
,Can
或Allow
And so on
func HasPrefix(name string, prefixes []string) bool{... }func IsEntry(name string, entries []string) bool{... }func CanManage(name string) bool{... }func AllowGitHook(a) bool{... }Copy the code
The interface name
By convention, interfaces that contain only one method should be named with the method name suffix -er, such as Reader, Writer, Formatter/CloseNotifier, and so on.
Nouns are used for interface names and verbs are used for interface method names.
type Reader interface {
Read(p []byte) (n int, err error)
}
Copy the code
Error
Error
The type is named afterError
At the end
type ParseError struct {
Line, Col int
}
Copy the code
Error
Type variable toErr
At the beginning
var ErrBadAction = errors.New("somepkg: a bad action was performed")
Copy the code
- Return type is
Error
Variable abbreviation adoptederr
func foo(a) {
res, err := somepkgAction()
iferr ! =nil {
if err == somepkg.ErrBadAction {
}
if pe, ok := err.(*somepkg.ParseError); ok {
line, col := pe.Line, pe.Col
/ /...}}}Copy the code
other
The name of the package content cannot start with the package name, because the package name does not need to be repeated
The HTTP package provides an HTTP service named http.server, not HTTPServer. User code references this type through http.server, so there is no ambiguity.
The type names in different packages can be the same because clients can distinguish them by package names
For example, the library contains several types named Reader, including JPEG.Reader, bufio.Reader, and Csv.reader. Each package name with Reader is a good type name.
List of abbreviations
acronym | instructions |
---|---|
ctx |
Context Or related, for examplegin.Context |
A semicolon
Go is actually a semicolon; But Go, like JavaScript, does not recommend adding a semicolon to the end of a single statement, because the compiler automatically adds a semicolon.
Statements like the following are perfectly fine:
go func(a) { for { dst <- <-src } }()
Copy the code
Typically, Go programs use semicolons only in places such as for loop clauses to separate initializers, conditions, and incremental elements. If you write multiple statements on a single line, separate them with semicolons.
iferr := f(); err ! =nil {
g()
}
Copy the code
For this reason, the opening brace of a function or control statement should never be placed on the next line.
if i < f() / / an error
{ / / an error
g()
}
Copy the code
parentheses
Control structures (if, for, and switch) do not require parentheses, not syntactically
The document
README, project document, interface document, etc., Chinese document typesetting reference: Chinese copy typesetting refers to north
annotation
-
All exported objects must be annotated to indicate their purpose, while non-exported objects are annotated as appropriate
-
Use the singular and continuous tense uniformly if the object is countable and there is no specified number; use the plural otherwise
-
Package, function, method, and type annotations are all one complete sentence
-
The first letter of a sentence type must be uppercase, and the first letter of a phrase type must be lowercase
-
The single line length of a comment cannot exceed 80 characters. If it exceeds 80 characters, force a line break
-
Comments for exportable objects must begin with the name of the object
// FileInfo is the interface that describes a file and is returned by Stat and Lstat
type FileInfo interface{...// HasPrefix returns true if name has any string in given slice as prefix
func HasPrefix(name string, prefixes []string) bool{...Copy the code
Single line comment & multi-line comment
-
Two comment styles, single line comment //, multi-line comment /*… * /
-
Multiline comments are only used for package-level document comments, except for single-line comments. Package comments are typically placed in the doc.go file, which contains only the content of the document comments
-
Please separate a single line comment symbol from the content with a space
Bad:
//Comments
Copy the code
Good:
// Comments
Copy the code
GoLand can be set to automatic formatting:
Preferences > Editor > Code Style > Go > Other Check Add leading space to comments
Package comments
-
Package-level comments are an introduction to a package and need only be specified in any source file for the same package to be effective
-
For the main package, there is typically a one-line comment that describes the purpose of the package, starting with the project name
// Write project description
package main
Copy the code
-
For subpackages of a complex project, package-level annotations are generally not required, except for modules that represent a particular function
-
Simple non-main packages can also be summarized with a one-line comment
-
For relatively complex non-main packages, examples or basic instructions will be added, starting with Package
/* Package http provides HTTP client and server implementations. ... * /
package http
Copy the code
- Extremely complex package specifications that can be created separately
doc.go
Documents to illustrate
Functions and Methods
- If one sentence is not enough, a line break can continue with a more detailed description
// Copy copies file from source to target path.
// It returns false and error when error occurs in underlying function calls.
Copy the code
- If the function or method is of judgment type (the return value is mainly
bool
Type), then<name> returns true if
At the beginning
// HasPrefix returns true if name has any string in given slice as prefix.
func HasPrefix(name string, prefixes []string) bool{...Copy the code
Structure, interface, and other types
- Definitions of types are usually singular:
// Request represents a request to run a command.
type Request struct{...Copy the code
- If it is an interface, it is generally described in the following format:
// FileInfo is the interface that describes a file and is returned by Stat and Lstat.
type FileInfo interface{...Copy the code
- If the structure has many attributes, add comments to the attributes
// Var variable for expression
type Var struct {
Key string `json:"key"` // variable key
Value interface{} `json:"value"` // value
Desc string `json:"desc"` // variable description
}
Copy the code
Other instructions
-
A comment at the beginning of TODO: can be used to alert maintenance personnel when a section is waiting to complete.
-
A comment at the beginning of FIXME: can be used to alert maintenance personnel when a part has known problems that need to be fixed or improved.
-
NOTE: When you need to specify something, you can use it.
// NOTE: os.Chmod and os.Chtimes don't recognize symbolic link,
// which will lead "no such file or directory" error.
return os.Symlink(target, dest)
Copy the code
formatting
We don’t have much of a choice because Go is already regulated and there are no such wars in the Go world.
The indentation
The indent must contain four Spaces and the TAB character is disabled.
EditorConfig Settings:
[{Makefile,go.mod,go.sum,*.go}]
indent_style = tab
indent_size = 4
Copy the code
Or GoLand Settings:
Preferences > Editor > Code Style > Go > Tabs and Indents
A blank line
- Add blank lines to keep paragraphs clear
other
Grouping and ordering of functions
- Functions should be ordered in rough order of invocation
- Functions in the same file should be grouped by receiver
- The exported function should appear in the file first, placed in
struct
,const
和var
After the definition. - One may appear after the type is defined, but before the rest of the receiver’s methods
newXYZ()
/NewXYZ()
. - Because functions are grouped by receiver, common utility functions should appear at the end of the file.
- So, generally one
struct
And related methods are organized into a file.
Bad:
func (s *something) Cost(a) {
return calcCost(s.weights)
}
type something struct{... }func calcCost(n int[]) int{... }func (s *something) Stop(a){... }func newSomething(a) *something {
return &something{}
}
Copy the code
Good:
type something struct{... }func newSomething(a) *something {
return &something{}
}
func (s *something) Cost(a) {
return calcCost(s.weights)
}
func (s *something) Stop(a){... }func calcCost(n int[]) int{... }Copy the code
Reduce the nested
Bad:
for _, v := range data {
if v.F1 == 1 {
v = process(v)
if err := v.Call(); err == nil {
v.Send()
} else {
return err
}
} else {
log.Printf("Invalid v: %v", v)
}
}
Copy the code
Good:
for _, v := range data {
ifv.F1 ! =1 {
log.Printf("Invalid v: %v", v)
continue
}
v = process(v)
iferr := v.Call(); err ! =nil {
return err
}
v.Send()
}
Copy the code
Unnecessary else
- Most of the time, we can extract code from the else branch as initialization.
Bad:
var a int
if b {
a = 100
} else {
a = 10
}
Copy the code
Good:
a := 10
if b {
a = 100
}
Copy the code
Global variable declaration
- Global variables, must be used
var
The keyword - Do not specify a type unless it is different from the type of the expression
Bad:
var a string = "abc"
var s string = F()
func F(a) string { return "A" }
Copy the code
Good:
var a = "abc"
Since F() already explicitly returns a string type, there is no need to explicitly specify the type of s
var s = F()
func F(a) string { return "A" }
Copy the code
- Specify the type if the type of the expression does not exactly match the desired type
type myError struct{}
func (myError) Error(a) string { return "error" }
func F(a) myError { return myError{} }
var err error = F()
// F() returns an instance of type myError, but we want the error type
Copy the code
Local variable declaration
- If a variable is explicitly set to a value, use the short variable declaration form (
: =
)
Bad:
var s string = "abc"
Copy the code
Good:
s := "abc"
Copy the code
- If the variable is dedicated to a reference
var
Keywords are more appropriate
func s(a) {
var s string
f(&s)
}
Copy the code
- If the variable is a return value, it is defined in the function return type
func f(list []int) (filtered []int) {
for _, v := range list {
if v > 10 {
filtered = append(filtered, v)
}
}
return
}
Copy the code
Import Package import grouping and sorting
- If multiple packages are imported into the same file, group them
- Standard package, third party package, custom package, respectively grouped, empty line separated, sorted
Bad:
import "a"
import "golang.org/x/sys"
import "runtime"
import "github.com/gin-gonic/gin"
import "b"
import "fmt"
Copy the code
Good:
import (
"fmt"
"runtime"
"a"
"b"
"github.com/gin-gonic/gin"
"golang.org/x/sys"
)
Copy the code
GoLand Settings are as follows:
Group similar declarations
For declarations such as var, const, type, etc:
- Put similar declarations in a group
Bad:
const a = 1
const b = 2
var a = 1
var b = 2
type Area float64
type Volume float64
Copy the code
Good:
const (
a = 1
b = 2
)
var (
a = 1
b = 2
)
type (
Area float64
Volume float64
)
Copy the code
- Place only related declarations in a group, never unrelated declarations in a group
Bad:
type Operation int
const (
Add Operation = iota + 1
Subtract
Multiply
RoleName = "Role Name"
)
Copy the code
Good:
type Operation int
const (
Add Operation = iota + 1
Subtract
Multiply
)
const RoleName = "Role Name"
Copy the code
- There is no limit to where groups can be used, and groups can also be used within functions
Bad:
func f(a) string {
var red = color.New(0xff0000)
var green = color.New(0x00ff00)
var blue = color.New(0x0000ff)
// ...
}
Copy the code
Good:
func f(a) string {
var (
red = color.New(0xff0000)
green = color.New(0x00ff00)
blue = color.New(0x0000ff))// ...
}
Copy the code
Function/method argument/return type order
- Simple types take precedence over complex types
Bad:
func F(u User, n int) {}
Copy the code
Good:
func F(n int, u User) {}
Copy the code
- If possible, put parameters of the same type next to each other, then you only need to write the type once
Bad:
func F(a int, c string, b int) {}
Copy the code
Good:
func F(a, b int, c string) {}
Copy the code
error
Always the last return type
Bad:
func F(a) (error, int) {}
Copy the code
Good:
func F(a) (int, error) {}
Copy the code
Order of structure attributes
Let’s start with an example:
Structure A – Definition:
struct {
a string
c string
b bool
d bool
}
Copy the code
Structure A – size 40, memory layout diagram:
Contrast, structure B – definition:
struct {
a string
b bool
c string
d bool
}
Copy the code
Structure B – size 48, memory layout diagram:
We found that the size of memory and layout of the structure were completely different depending on the order of its attributes.
So we have a convention: try to put attributes of the same type together. That is, the order of definitions in structure A is recommended.
Embeddedness in a structure
The embedded type (such as MUtex) should be at the top of the list of fields in the body of the structure, and there must be a blank line separating the embedded field from the regular field.
Bad:
type Client struct {
version int
http.Client
}
Copy the code
Good:
type Client struct {
http.Client
version int
}
Copy the code
The field name must be specified when initializing the structure
The field name must be specified when initializing the structure, otherwise the relevant tools and Review will not give it. If not specified, code refactoring can have unexpected consequences.
Bad:
k := User{"John"."Doe".true}
Copy the code
Good:
k := User{
FirstName: "John",
LastName: "Doe",
Admin: true,}Copy the code
The only exception: if there are three or fewer fields, you can omit field names from the test table
tests := []struct{
}{
op Operation
want string
}{
{Add, "add"},
{Subtract, "subtract"}},Copy the code
Reduce the scope of variables
- If possible, minimize the scope of a variable unless it conflicts with rules that reduce nesting
Bad:
err := ioutil.WriteFile(name, data, 0644)
iferr ! =nil {
return err
}
Copy the code
Good:
if err := ioutil.WriteFile(name, data, 0644); err ! =nil {
return err
}
Copy the code
- If you need to use the results of a function call outside of if, you should not try to narrow it down
Bad:
if data, err := ioutil.ReadFile(name); err == nil {
err = cfg.Decode(data)
iferr ! =nil {
return err
}
fmt.Println(cfg)
return nil
} else {
return err
}
Copy the code
Good:
data, err := ioutil.ReadFile(name)
iferr ! =nil {
return err
}
iferr := cfg.Decode(data); err ! =nil {
return err
}
fmt.Println(cfg)
return nil
Copy the code
Error messages should not be capitalized or punctuated
Bad:
fmt.Errorf("Something bad.")
Copy the code
Good:
fmt.Errorf("something bad")
Copy the code
The Error description needs to be wrapped or referenced, so the following code tells us why it should not:
log.Printf("Reading %s: %v", filename, err)
Copy the code
slice
Nil is a slice with a valid length of 0
- Zero-value slices are available immediately without a call to make
Bad:
nums := []int{}
// or, nums := make([]int, 0)
if add1 {
nums = append(nums, 1)}Copy the code
Good:
var nums []int
if add1 {
nums = append(nums, 1)}Copy the code
- To check if the slice is empty, always use
len(s) == 0
, don’t checknil
Bad:
func isEmpty(s []string) bool {
return s == nil
}
Copy the code
Good:
func isEmpty(s []string) bool {
return len(s) == 0
}
Copy the code
- For slices that need serialization, you must initialize them using make
Bad:
var v []int
s, _ := json.Marshal(v)
println(string(s))
// output: null
Copy the code
Good:
v := make([]int.0)
s, _ := json.Marshal(v)
println(string(s))
// output: []
Copy the code
The resources
- Package names – Go Blog
- Style guideline for Go packages
- Organizing Go code – Go Blog
- How to Write Go Code – Go Blog
- Effective Go
- Go Code Convention
- Go Wiki – Errors
- Uber Go Style Guide