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 generate
The 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
- run
go generate
Command, the command following the special comment is executed - Special comments must begin with
//go:generate
At 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
- when
go generate
If 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 ~