Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”

This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

What do you do when you define error codes at work? XDM can be exchanged in the comments section

I’ve seen error codes defined like this:

m := make(map[int]string)
m[0] = "OK"
m[1] = "Link failed"
m[2] = "File type error".Copy the code

Error codes are defined as follows:

type myErr struct {
	code   int
	err    error
	extMsg interface{}
}

myOk := myErr{0,errors.New("PROCESS OK"),"xxx"}
myOk := myErr{1,errors.New("File type error"),"xxx"}
myOk := myErr{2,errors.New("Database connection failed"),"xxx"}...Copy the code

Some have seen it done:

const (
	ERR_OK          = 0
	ERR_CONN_REFUSE = 1
	ERR_FILE_NOT    = 2
)


var m = map[int]string{
    ERR_OK:          "OK",
    ERR_CONN_REFUSE: "Link rejected",
    ERR_FILE_NOT:    "File does not exist",}Copy the code

Now there is a better way to implement the mapping of error codes in our work

The introduction of the go generate

Let’s introduce Go generate, which can be achieved by defining error codes and writing annotations. When we call error codes, the desired error information can be correctly output

Here’s an example:

Let’s create the following directory and put the error code file errcode.go in a separate package

. ├ ─ ─ go. Mod ├ ─ ─ main. Go └ ─ ─ mycodes └ ─ ─ errcode. GoCopy the code

We also need to use the Stringer tool to help us achieve this goal

go get golang.org/x/tools/cmd/stringer
Copy the code

Let’s take a look at the contents of the above document:

./mycodes/errcode.go

/* ____ ___ _____ ___________ \ \/ / / \\__ ___/ \ / / \ / \ | | / \ / Y \| | /___/\ \\____|__ /|____| \_/ \/ CreateTime :2021/10/10 createUser:Administrator */ package mycodes type ErrCode int64 const (ERR_CODE_OK ErrCode = 0 // PROCESS OK ERR_CODE_INVALID_PARAMS ErrCode = 1 // Parameter invalid ERR_CODE_TIMEOUT ErrCode = 2 // Timeout ERR_CODE_FILE_NOT_EXIST ERR_CODE_CONN_REFUSE ErrCode = 4 // Connection rejected ERR_CODE_NET_ABNORMAL ErrCode = 5 // Network exception)Copy the code

main.go

/*
____  ___   _____ ___________
\   \/  /  /     \\__    ___/
 \     /  /  \ /  \ |    |
 /     \ /    Y    \|    |
/___/\  \\____|__  /|____|
      \_/        \/
createTime:2021/10/10
createUser:Administrator
*/
package main

import (
        "fmt"
        "myerr/mycodes"
)

func main() {
        fmt.Println(mycodes.ERR_CODE_CONN_REFUSE)
}

Copy the code

Let’s initialize the go module in main.go, go mod init myErr

go.mod

The module myerr go 1.15Copy the code

To demonstrate

Go directly to go run main.go in the same directory as main.go, the output is as follows:

4
Copy the code

Is the enumeration value 4 corresponding to ERR_CODE_CONN_REFUSE, but we do not expect this class, we expect to directly output the error message corresponding to the error code

Use the stringer

Manually use the Stringer tool you just installed in the MyCodes directory

stringer -linecomment -type ErrCode 
Copy the code

Where ErrCode is the type of error code, mycodes generate a file errcode_string.go after executing the above statement, and now the directory structure looks like this

.├ ── └.go ├── MyCodes ├─ go ├.go ├── go ├.go ├.goCopy the code

Take a look at the errcode_string.go content

// Code generated by "stringer -linecomment -type ErrCode"; DO NOT edit. package mycodes import "strconv" const _ErrCode_name = "PROCESS OK parameter invalid timeout file no connection rejected network exception "var _ErrCode_index = [...]. uint8{0, 10, 22, 28, 43, 58, 70} func (i ErrCode) String() string { if i < 0 || i >= ErrCode(len(_ErrCode_index)-1) { return "ErrCode(" + strconv.FormatInt(int64(i), 10) + ")" } return _ErrCode_name[_ErrCode_index[i]:_ErrCode_index[i+1]] }Copy the code

We can see that stringer tool can realize the mapping of error code and string by combining all the strings mapped by our error code information into the _ErrCode_name constant, with _ErrCode_index as the index value of each error code mapping string. This one is pretty easy

Results show

At this point, we still execute go run main.go in the same directory as main.go, and the output is as follows:

Connection rejectedCopy the code

Display the formal error message we expect

Stringer tools

Let’s take a look at the help of stringer tools to learn a wave in detail

# stringer -h
Usage of stringer:
        stringer [flags] -type T [directory]
        stringer [flags] -type T files... # Must be a single package
For more information, see:
        http://godoc.org/golang.org/x/tools/cmd/stringer
Flags:
  -linecomment
        use line comment text as printed text when present
  -output string
        output file name; default srcdir/<type>_string.go
  -trimprefix prefix
        trim the prefix from the generated constant names
  -type string
        comma-separated list of type names; must be set
Copy the code

You can see that there are two big uses:

 stringer [flags] -type T [directory]
 stringer [flags] -type T files... # Must be a single package
Copy the code

The first can be followed by a directory of type T

The second way is to specify an explicit file after type T, but this way must be in a separate package

The parameters are as follows:

  • -linecomment

Use the line comment text as the printed text

  • -output string

Output file name; The default source directory is / < type > _string.go, so we can see in the example that our output file is errcode_string.go under myCodes

  • -trimprefix prefix

Trim the prefix from the generated constant name

  • -type string

A comma-separated list of type names. This parameter must be set

go generate

We used the Stringer tool on the command line, so we needed to use the Go Generate tool to put this stuff into the project code

Get a sense of what Go Generate is

Go generate is a built-in tool of Go, which can be viewed from the command line:

# go
Copy the code

Let’s check out the help document go Help generate

# go help generate. Go generate scans the file for directives, which are lines of the form, //go:generate command argument... . Go generate sets several variables when it runs the generator: $GOARCH The execution architecture (arm, amd64, etc.) $GOOS The execution operating system (linux, windows, etc.) $GOFILE The base name of the file. $GOLINE The line number of the directive in the source file. $GOPACKAGE The name of the package of the file containing the directive. $DOLLAR A dollar sign.Copy the code

These are the environment variables for use with Go Generate

  • $GOARCH

Architecture (ARM, AMD64, etc.)

  • $GOOS

Current OS environment (Linux, Windows, etc.)

  • $GOFILE

The name of the file being processed

  • $GOLINE

The line number of the current command in the file

  • $GOPACKAGE

The package name of the file currently being processed

go generateThe command format

go generate [-run regexp] [-n] [-v] [-x] [command] [build flags] [file.go... | packages]
Copy the code
The parameters are described as follows: -run Matches the command line and only the matched command is executed. -v Displays the package name and source file name to be processed. -n Indicates that the command is not executed. -x Displays and executes commands. Command can be any command in the environment variable PATH.Copy the code

The generate usage

//go:generate command argument… Use the generate tool

The actual case

So let’s try it out a little bit

We added the generate statement to main.go and executed ls-alh with generate

/*
____  ___   _____ ___________
\   \/  /  /     \\__    ___/
 \     /  /  \ /  \ |    |
 /     \ /    Y    \|    |
/___/\  \\____|__  /|____|
      \_/        \/
createTime:2021/10/10
createUser:Administrator
*/
package main

//go:generate ls -alh

import (
        "fmt"
        "myerr/mycodes"
)

func main() {
        fmt.Println(mycodes.ERR_CODE_CONN_REFUSE)
}
Copy the code

Run go generate in the same directory as main.go to see the effect

# go generateTotal 20K DRWxr-XR-x 3 root root 4.0K Oct 10 17:30. Drwxr-xr-x 11 root root 4.0K Oct 10 16:25.. -rw-r--r-- 1 root root 22 Oct 10 16:02 go.mod -rw-r--r-- 1 root root 346 Oct 10 17:30 main.go drwxr-xr-x 2 root root 4.0K Oct 10 17:13 MyCodesCopy the code

Ls-alh succeeded

Use of Go Generate + Stringer

So let’s add the Stringer tool that we’ve been experimenting with

So the directory looks like this

. ├ ─ ─ go. Mod ├ ─ ─ main. Go └ ─ ─ mycodes └ ─ ─ errcode. GoCopy the code

Main.go looks like this

/*
____  ___   _____ ___________
\   \/  /  /     \\__    ___/
 \     /  /  \ /  \ |    |
 /     \ /    Y    \|    |
/___/\  \\____|__  /|____|
      \_/        \/
createTime:2021/10/10
createUser:Administrator
*/
package main

//go:generate stringer -linecomment -type ErrCode ./mycodes

import (
        "fmt"
        "myerr/mycodes"
)

func main() {
        fmt.Println(mycodes.ERR_CODE_CONN_REFUSE)
}

Copy the code

//go:generate stringer -linecomment -type ErrCode./mycodes

Just run go generate -x and see what happens

# go generate -x
stringer -linecomment -type ErrCode ./mycodes
Copy the code

Errcode_string. go is generated again

.├ ── └.go ├── MyCodes ├─ go ├.go ├── go ├.go ├.goCopy the code

Go run main. Go must of course be what we want

# go run main.goConnection rejectedCopy the code

Specification for use of Go Generate

  • rungo generateCommand, the command following the special comment is executed
  • Special comments must begin with//go:generateAt the beginning, there is no space after a double slash
  • This special comment must be in the.go source file
  • Each source file can contain multiple generate special comments
  • whengo generateIf a command execution error occurs, the program is terminated

Finally, what else can Go Generate do

// Go :generate Can also be used to generate executable programs, such as // Go :generate.

  • Protobuf: generates a.pb.go file from the protocol buffer definition file (.proto), which is used for GRPC communication
  • Yacc: generates the. Go file from the. Y file
  • HTML: Embed HTML files into the GO source code
  • Bindata: Converts files such as JPeGs into byte arrays in go code
  • Unicode: Generate Unicode tables from unicodedata.txt

A tool is valuable only when it is used

Welcome to like, follow and favorites

Friends, your support and encouragement, I insist on sharing, improve the quality of the power

All right, that’s it for this time

Technology is open, our mentality, should be more open. Embrace change, live in the sun, and strive to move forward.

I am Nezha, welcome to like, see you next time ~