Go code specification sorting

Go Code Review

Summarize several code specification errors that are often made in the development process

Reference link: https://learnku.com/go/wikis/48375

Comment statement

// Request indicates the request to run the command.
type Request struct { ...

// Encode writes the JSON encoding of req to w.
func Encode(w io.Writer, req *Request) { ...

context

Most functions that use context take it as the first parameter

func F(ctx context.Context, /* Other parameters */) {}

Adding a context as a member to a structure type is not recommended

// Not recommended
type MyContext struct {
    ctx context.Context
}

Crypto Rand

Do not use math/rand to generate keys, even one-time keys. Without seed, the generator can be predicted completely. Please use crypto/rand Reader instead

func Key() string {
	buf := make([]byte, 16)
	_, err := rand.Read(buf)
	if err != nil {
		panic(err) // Out of randomness, it will never happen
	}
	return fmt.Sprintf("%x", buf)
	// or hex.EncodeToString(buf)
	// or base64.StdEncoding.EncodeToString(buf)
}

func main() {
	fmt.Println(Key())
}
//output
//4799b801e7866209593cfaedb03cf8da

Declare an empty slice

When declaring an empty slice, it is preferred to use

var t []string

instead of

t := []string{}

The former declares a nil slice value, while the latter declares a non nil but zero length slice. Both are functionally equivalent, len and cap are zero, and nil slice is the preferred style.

Please note that in some scenarios, non nil but zero length slices are preferred. For example, when encoding JSON objects (NIL slices are encoded as null, and [] string {} can be correctly encoded as JSON array []).

Package comments

/*
Package template implements data-driven templates for generating textual
output such as HTML.
....
*/
package template

If the package is simple, the package comments can be short.

// Package math provides basic constants and mathematical functions.
package math

Package name

All references to the name in the package will be done with the package name, so you can omit the name from the identifier. For example, if you are using the chubby package, you do not need to type chubbyfile because the client will write it as chubby ChubbyFile. On the contrary, in this way named file, the client will write it as chubby File . Avoid meaningless package names like util, common, misc, api, types, and interfaces.

No, Panic

error message

That is, use FMT Errorf ("something bad") instead of FMT Errorf("Something bad")

Import of packages

Avoid renaming and importing packages to prevent name conflicts; A good package name does not need to be renamed. If there is a naming conflict, you prefer to rename the package closest to the local or project specific package.

Package import is organized by groups, and there are blank lines between groups. Standard library packages are always in the first group.

package main

import (
    "fmt"
    "hash/adler32"
    "os"

    "appengine/foo"
    "appengine/user"

    "github.com/foo/bar"
    "rsc.io/goversion/version"
)

Anonymous import of packages

Import_ The "PKG" import statement should only exist in main Go file

Dot import

package foo_test

import (
    . "foo"
)

Do not use import. In your program. It will make the program more difficult to read

Inline error

Nonstandard writing

// Find the value of the return key. If there is no key mapping, an empty string is returned.
func Lookup(key string) string

Standard writing

// Find and return the value of the key. If there is no key mapping, ok = false.
func Lookup(key string) (value string, ok bool)

And help write more robust and readable code:

value, ok := Lookup(key)
if !ok {
    return fmt.Errorf("no value for %q", key)
}
return Parse(value)

Indent error handling

To indent error handling logic, do not indent regular code. This can improve the readability of the code, and readers can quickly browse the logical trunk. For example, do not write:

if x, err := f(); err != nil {
    // error handling
    return
} else {
    // Use variable x
}

Instead, it should read:

x, err := f()
if err != nil {
    // error handling
    return
}
// Use variable x

The benefits of this writing can increase readability

Acronym

Words in names that are initials or acronyms (such as "Url" or "NATO") need to have the same case rules. For example, "Url" should appear as "Url" or "Url" (such as "urlpony" or "urlpony") instead of "Url". For example: ServeHttp is not ServeHttp. Identifiers with multiple initialization "words" should also be displayed as "XMLHTTPRequest" or "XMLHTTPRequest".

When "ID" is the abbreviation of "identifier", this rule also applies to "ID", so please write "appId" instead of "appId".

The code generated by protocol buffer is an exception. The requirements for people and machines cannot be the same. The code written by people should maintain a higher standard than that written by machines.

Interface

In general, the Go interface should be included in the user's package, not the implementer's package. Implementers only need to return specific types (usually pointers or structs), so that new methods can be added to the implementation without extending refactoring.

Do not define the "for mocking" interface on the implementer side of the API; Instead, we need to define an open API and test it with a real implementation.

Don't define the interface first and then use it. Separated from the real use scenario, we can't determine whether an interface has the value of existence, let alone the method of designing the interface

It is suggested to separate the interface and the specific implementation class of the interface into two go files

package consumer  // consumer_func.go

type Thinger interface { Thing() bool }

func Foo(t Thinger) string { ... }
package consumer //consumer.go

type defaultThinger struct{ ... }
func (t defaultThinger) Thing() bool { ... }

func NewThinger() Thinger { return defaultThinger{ ... } }

Nonstandard writing

package producer

type Thinger struct{ ... }
func (t Thinger) Thing() bool { ... }

func NewThinger() Thinger { return Thinger{ ... } }

Method recipient naming

The name of the method recipient should reflect its identity; Usually, one or two acronyms of its type are sufficient (for example, "c" or "cl" for "client"). Do not use generic names, such as "me", "this" or "self", which are typical identifiers for object-oriented languages that give the method a special meaning.

Method recipient type

If you're not sure, use a pointer.

Variable name

The variable names in Go should be as short and concise as possible, especially for local variables in limited space. For example: use c instead of lineCount; Use i instead of sliceIndex.

Basic rule: when a variable is used for the first time, the farther away from the declared position, the variable name must be more descriptive. One or two letters are sufficient for the name of the method receiver. The names of common variables such as loop indexes and readers can be referred to by a letter (I, R).

Of course, for some complex logic, or unconventional things, or global variables, you need to use more descriptive names.

Keywords: Go Code Style

Added by mcdsoftware on Thu, 27 Jan 2022 02:37:53 +0200