听说你还在自己做重复劳动?看我一键生成错误码映射

简介: 大家在工作中定义错误码的时候都是如何处理的? xdm 可以评论区交流交流我看到过有的是这样定义错误码的

大家在工作中定义错误码的时候都是如何处理的? xdm 可以评论区交流交流

我看到过有的是这样定义错误码的:

m := make(map[int]string)
m[0] = "OK"
m[1] = "链接失败"
m[2] = "文件类型错误"
...

还看到过这样定义错误码的:

type myErr struct {
  code   int
  err    error
  extMsg interface{}
}
myOk := myErr{0,errors.New("PROCESS OK"),"xxx"}
myOk := myErr{1,errors.New("文件类型错误"),"xxx"}
myOk := myErr{2,errors.New("连接数据库失败"),"xxx"}
...

也有见到过这样做的:

const (
  ERR_OK          = 0
  ERR_CONN_REFUSE = 1
  ERR_FILE_NOT    = 2
)
var m = map[int]string{
    ERR_OK:          "OK",
    ERR_CONN_REFUSE: "链接被拒绝",
    ERR_FILE_NOT:    "文件不存在",
}

现在有一个更好的方法来实现我们工作中错误码的映射

引入 go generate

咱们引入 go generate ,可以只用定义错误码和写注释,就可以达到,当我们调用错误码的时候,能够正确的输出我们想要的错误信息

举个例子:

我们先建立如下目录,将错误码文件 errcode.go,放在一个单独的包里面

.
├── go.mod
├── main.go
└── mycodes
    └── errcode.go

我们还需要运用 stringer 工具,来辅助我们完成这个目标

go get golang.org/x/tools/cmd/stringer

我们来看看上述文件的内容:

./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 // 参数无效
        ERR_CODE_TIMEOUT        ErrCode = 2 // 超时
        ERR_CODE_FILE_NOT_EXIST ErrCode = 3 // 文件不存在
        ERR_CODE_CONN_REFUSE    ErrCode = 4 // 连接被拒绝
        ERR_CODE_NET_ABNORMAL   ErrCode = 5 // 网络异常
)

main.go

/*
____  ___   _____ ___________
\   \/  /  /     \\__    ___/
 \     /  /  \ /  \ |    |
 /     \ /    Y    \|    |
/___/\  \\____|__  /|____|
      \_/        \/
createTime:2021/10/10
createUser:Administrator
*/
package main
import (
        "fmt"
        "myerr/mycodes"
)
func main() {
        fmt.Println(mycodes.ERR_CODE_CONN_REFUSE)
}

我们在 main.go 统计目录下初始化一下 go 的 模块, go mod init myerr

go.mod

module myerr
go 1.15

开始演示

我们直接在 main.go 的同级目录下执行 go run main.go,输出如下:

4

是 ERR_CODE_CONN_REFUSE 对应的枚举值 4 ,可是我们期望的课不是这个,我们是期望能直接输出错误码对应的错误信息

使用 stringer

手动在 mycodes 目录下使用刚才安装的  stringer 工具

stringer -linecomment -type ErrCode 

此处的 ErrCode 是错误码的类型 , 执行上述语句后,mycodes 生成了一个文件 errcode_string.go ,现在目录结构是这样的

.
├── go.mod
├── main.go
└── mycodes
    ├── errcode.go
    └── errcode_string.go

看看 errcode_string.go 内容

// Code generated by "stringer -linecomment -type ErrCode"; DO NOT EDIT.
package mycodes
import "strconv"
const _ErrCode_name = "PROCESS OK参数无效超时文件不存在连接被拒绝网络异常"
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]]
}

我们可以看出 stringer 工具,将我们的错误码信息映射的字符串全部合并起来放在  _ErrCode_name 常量中,且有  _ErrCode_index  来作为每一个错误码映射字符串的索引值 ,最终便能实现错误码和字符串的映射,这个就很简单吧

效果展示

此时,我们仍然在 main.go 的同级目录下执行 go run main.go,输出如下:

shell

复制代码

连接被拒绝

显示的正式我们期望的错误信息

stringer 工具

我们来看看 stringer 工具的帮助,在来详细学习一波

# 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

可以看到大的用法有 2 种:

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

第一种可以在类型 T 后面加上目录

第二种可以指定类型 T 后面指定明确的文件,但是这种方式必须是在一个单独的包里面

参数如下:

  • -linecomment

使用行注释文本作为打印文本

  • -output string

输出文件名称;默认源目录下的 / <类型> _string.go,所以我们可以看到例子中我们的输出文件在 mycodes 下的 errcode_string.go

  • -trimprefix prefix

从生成的常量名称中修剪前缀

  • -type string

以逗号分隔的类型名称列表,这个参数是必须要设置的

go generate

刚才我们是在命令行中,使用 stringer 工具来生成的,那么我们要把这些东西放入项目代码中就需要使用  go generate 工具了

先大致了解一下 go generate 是个啥玩意

go generate 是 go 自带的一个工具,我们可以通过在命令行中查看到:

shell

复制代码

# go

image.png

咱们查看一下帮助文档 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.

上面这些是 go generate 使用时候的环境变量

  • $GOARCH

体系架构(arm、amd64 等)

  • $GOOS

当前的 OS 环境(linux、windows 等)

  • $GOFILE

当前处理中的文件名

  • $GOLINE

当前命令在文件中的行号

  • $GOPACKAGE

当前处理文件的包名

go generate命令格式

go generate [-run regexp] [-n] [-v] [-x] [command] [build flags] [file.go... | packages]

| packages]

参数说明如下:
-run 
正则表达式匹配命令行,仅执行匹配的命令;
-v 
输出被处理的包名和源文件名;
-n 
显示不执行命令;
-x 
显示并执行命令;
command 
可以是在环境变量 PATH 中的任何命令。

generate 用法

上面帮助文档有体现,我们可以使用 //go:generate command argument...  来讲 generate 工具用起来

实际案例

我们来简单的尝试一下

我们在刚才的 main.go 中加入 generate 的语句,使用 generate 执行,ls -alh

/*
____  ___   _____ ___________
\   \/  /  /     \\__    ___/
 \     /  /  \ /  \ |    |
 /     \ /    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)
}

在 main.go 同级目录下执行 go generate 看效果

# go generate
total 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 mycodes

果然是调用 ls -alh 成功了

go generate + stringer 的使用

那么我们就把刚才我们实践的 stringer  工具也加进去玩玩

此时目录是这样的

.
├── go.mod
├── main.go
└── mycodes
    └── errcode.go

main.go 是这样的

/*
____  ___   _____ ___________
\   \/  /  /     \\__    ___/
 \     /  /  \ /  \ |    |
 /     \ /    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)
}


没错我们加入了 //go:generate stringer -linecomment -type ErrCode ./mycodes

直接执行 go generate -x 来看效果吧

shell

复制代码

# go generate -xstringer -linecomment -type ErrCode ./mycodes

errcode_string.go 又生成了

.
├── go.mod
├── main.go
└── mycodes
    ├── errcode.go
    └── errcode_string.go

执行 go run main.go 当然必须是我们想要的东西啦

# go run main.go
连接被拒绝

go generate 的使用规范

  • 运行go generate命令时,才会执行特殊注释后面的命令
  • 特殊注释必须以//go:generate开头,双斜线后面没有空格
  • 该特殊注释必须在 .go 源码文件中
  • 每个源码文件可以包含多个 generate 特殊注释
  • go generate命令执行出错时,将终止程序的运行

最后说说 go generate 还能干些啥

go generate 能干的事情还真不少,只要是能够在 path 下面能找到的可执行程序,都可以放在 //go:generate 后面玩,一般使用 go generate 会有如下场景:

  • protobuf:从 protocol buffer 定义文件(.proto)生成 .pb.go 文件 , 这种情况 grpc 通信的时候常用
  • yacc:从 .y 文件生成 .go 文件
  • HTML:将 HTML 文件嵌入到 go 源码
  • bindata:将形如 JPEG 这样的文件转成 go 代码中的字节数组
  • Unicode:从 UnicodeData.txt 生成 Unicode 表

工具要用用起来才能体现它的价值


欢迎点赞,关注,收藏

朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力

image.png

好了,本次就到这里

技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。

我是阿兵云原生,欢迎点赞关注收藏,下次见~

相关文章
|
7月前
|
算法
数据·结构
数据·结构
|
2月前
|
API 开发者
提供一份 1688 商品详情接口的错误码及解决方法
本文介绍了 1688 商品详情接口常见的错误码及其解决方法,包括 401(未授权)、403(禁止访问)、404(未找到)、429(请求过多)和 500/502/504(服务器错误)。详细说明了每个错误码的含义及相应的解决步骤,帮助开发者快速定位并解决问题。
|
2月前
|
缓存 前端开发 安全
前端开发者必备:HTTP状态码含义与用途解析,常见错误码产生原因及解决策略
前端开发者必备:HTTP状态码含义与用途解析,常见错误码产生原因及解决策略
190 0
|
4月前
|
JSON Java 对象存储
Java系统中的错误码设计问题之ProblemBuilder构建错误如何解决
Java系统中的错误码设计问题之ProblemBuilder构建错误如何解决
31 1
|
4月前
|
Java 对象存储 开发者
Java系统中的错误码设计问题之设计包含context错误消息的规范如何解决
Java系统中的错误码设计问题之设计包含context错误消息的规范如何解决
21 0
|
Cloud Native Linux Go
听说你还在自己做重复劳动?看我一键生成错误码映射
听说你还在自己做重复劳动?看我一键生成错误码映射
|
7月前
|
小程序 定位技术 Android开发
小程序质量提升丨定位问题解决方案(错误码11)
小程序质量提升丨定位问题解决方案(错误码11)
119 6
|
程序员 开发者
程序员在写code和做管理二者选择时,要切合自身实际来定
写代码还是做管理,这是个老生常谈的命题,就像某明星被离婚一样,隔一段时间就会被提出来供大家讨论。虽然这次话题是这个命题,那就好好的再来聊一次程序员的职业生涯是一直写代码呢还是从写代码转到做管理呢?再借用莎士比亚写的哈姆雷特经典桥段:“生存还是毁灭,这是个问题”,这里我来改编一下:“写代码还是做管理,这是个问题”。
97 0
程序员在写code和做管理二者选择时,要切合自身实际来定
|
前端开发
前端工作总结166-地址里面返回参数
前端工作总结166-地址里面返回参数
70 0
前端工作总结166-地址里面返回参数
|
Rust Java 程序员
什么是好的错误消息? 讨论一下Java系统中的错误码设计
一个好的Error Message主要包含三个部分:Context: 什么导致了错误?发生错误的时候代码想做什么?The error itself: 到底是什么导致了失败?具体的原因和当时的数据是什么?Mitigation: 有什么解决方案来克服这个错误,也可以理解为 Solutions。听起来还是有点抽象,能否给点代码具体说明下?
什么是好的错误消息? 讨论一下Java系统中的错误码设计