大家在工作中定義錯誤碼的時候都是如何處理的? 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
,輸出如下:
連線被拒絕
顯示的正式我們期望的錯誤資訊
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 自帶的一個工具,我們可以透過在命令列中檢視到:
# go
我們們檢視一下幫助文件 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]
引數說明如下:
-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 來看效果吧
# go generate -x
stringer -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 表
工具要用用起來才能體現它的價值
歡迎點贊,關注,收藏
朋友們,你的支援和鼓勵,是我堅持分享,提高質量的動力
好了,本次就到這裡
技術是開放的,我們的心態,更應是開放的。擁抱變化,向陽而生,努力向前行。
我是阿兵雲原生,歡迎點贊關注收藏,下次見~