golang简单错误处理与分类原语插件库errors的使用
Golang简单错误处理与分类原语插件库errors的使用
errors
包提供了简单的Golang错误和分类原语。
Class
包定义了一个极速的分类系统。Class
是一个uint32包装器,由Major
、Minor
和Index
子分类组成。每个子分类有不同的位长度:Major占8位,Minor占10位,Index占14位,总共32位。
示例:
00000010101000101000010011001111 分解为:
00000010 - major (8 bit)
1010001010 - minor (10 bit)
00010011001111 - index (14 bit)
Class可以通过三种方式组成:
- 仅Major - Class是Major单例
- Major和Minor - 不需要三重子分类
- Major、Minor和Index - 需要分解
使用NewMajor
或MustNewMajor
函数创建Major
,NewMinor
或MustNewMinor
创建Minor
,NewIndex
或MustNewIndex
创建Index
。
接口
包提供了简单的错误处理接口和函数,可以创建简单和详细的分类错误。
ClassError
ClassError
接口通过Class
方法提供错误分类。
DetailedError
DetailedError
是用于存储和处理人类可读细节、包含实例ID和运行时调用操作的错误接口。实现了ClassError
、Detailer
、Operationer
、Indexer
和error
接口。
Detailer
Detailer
接口允许设置和获取人类可读的细节 - 完整句子。
Operationer
OperationError
接口用于获取运行时操作信息。
Indexer
Indexer
接口用于获取每个错误实例的唯一’ID’。
错误处理
包包含两种错误结构实现:
- 简单错误结构
- 详细错误结构
简单错误
简单错误实现了ClassError
接口。它是轻量级错误,仅包含消息和其类。
使用New
和Newf
函数创建。
示例:
import "github.com/neuronlabs/errors"
// 假设我们已经定义了一些ClassInvalidRequest
var ClassInvalidInput errors.Class
func createValue(input int) error {
if input < 0 {
return errors.New(ClassInvalidInput, "provided input lower than zero")
}
if input > 50 {
return errors.Newf(ClassInvalidInput, "provided input value: '%d' is not valid", input)
}
// 执行逻辑
return nil
}
详细错误
详细错误结构(detailedError
)实现了DetailedError
。
它包含关于给定错误实例的许多信息:
- 人类可读的
Details
- 运行时函数调用
Operations
- 唯一错误实例
ID
使用NewDet
或NewDetf
函数创建详细错误。
示例
import (
"fmt"
"os"
"github.com/neuronlabs/errors"
)
var (
ClInputInvalidValue errors.Class
ClInputNotProvided errors.Class
)
func init() {
initClasses()
}
func initClasses() {
inputMjr := errors.MustNewMajor()
invalidValueMnr := errors.MustNewMinor(inputMjr)
ClInputInvalidValue = errors.MustNewMinorClass(inputMjr, invalidValueMnr)
inputNotProvidedMnr := errors.MustNewMinor(inputMjr)
ClInputNotProvided = errors.MustNewMinorClass(inputMjr, inputNotProvidedMnr)
}
func main() {
input, err := getInput()
if err == nil {
// 一切正常
os.Exit(0)
}
if classed, ok := err.(errors.ClassError); ok {
if classed.Class() == ClInputNotProvided {
fmt.Println("No required integer arguments provided.")
os.Exit(1)
}
}
var details string
detailed, ok := err.(errors.DetailedError)
if ok {
details = detailed.Details()
} else {
details = err.Error()
}
fmt.Printf("Invalid input value provided: '%s'\n", details)
os.Exit(1)
}
func checkInput(input int) error {
if input < 0 {
err := errors.NewDet(ClassInputInvalidValue, "provided input lower than zero")
err.SetDetailsf("The input value provided to the function is invalid. The value must be greater than zero.")
return err
}
if input > 50 {
err := errors.NewDetf(ClassInvalidInput, "provided input value: '%d' is not valid", input)
err.SetDetailsf("The input value: '%d' provided to the function is invalid. The value can't be greater than '50'.", input)
return err
}
// 执行逻辑
return nil
}
func getInput() (int, error) {
if len(os.Args) == 0 {
return errors.New(ClInputNotProvided, "no input provided")
}
input, err := strconv.Atoi(os.Args[0])
if err != nil {
err := errors.NewDetf(ClInputInvalidValue, "provided input is not an integer")
err.SetDetail(err.Error())
return 0, err
}
if err = checkInput(input); err != nil {
return 0, err
}
return input, nil
}
更多关于golang简单错误处理与分类原语插件库errors的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang简单错误处理与分类原语插件库errors的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang 错误处理与分类:errors库的使用
在Go语言中,错误处理是一个核心概念。标准库提供了基本的错误处理机制,而第三方库如github.com/pkg/errors
提供了更强大的功能。下面我将介绍如何使用这些工具进行错误处理和分类。
标准库错误处理
Go标准库提供了基本的错误接口和创建方法:
package main
import (
"errors"
"fmt"
)
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}
func main() {
result, err := divide(10, 0)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Println("Result:", result)
}
pkg/errors 库
github.com/pkg/errors
提供了更强大的错误处理功能:
安装
go get github.com/pkg/errors
基本用法
package main
import (
"fmt"
"github.com/pkg/errors"
)
func readFile() error {
// 模拟底层错误
return errors.New("file not found")
}
func process() error {
err := readFile()
if err != nil {
return errors.Wrap(err, "process failed")
}
return nil
}
func main() {
err := process()
if err != nil {
fmt.Printf("Error: %+v\n", err)
// 输出:
// Error: process failed: file not found
// main.process
// /path/to/file.go:15
// main.main
// /path/to/file.go:21
}
}
错误分类
package main
import (
"fmt"
"github.com/pkg/errors"
)
// 定义错误类型
var (
ErrNotFound = errors.New("not found")
ErrUnauthorized = errors.New("unauthorized")
)
func checkAccess(role string) error {
if role != "admin" {
return errors.Wrap(ErrUnauthorized, "access denied")
}
return nil
}
func main() {
err := checkAccess("user")
switch {
case errors.Is(err, ErrUnauthorized):
fmt.Println("Unauthorized access attempt")
fmt.Printf("Original error: %v\n", errors.Cause(err))
case errors.Is(err, ErrNotFound):
fmt.Println("Resource not found")
default:
fmt.Println("Unknown error")
}
}
高级用法
package main
import (
"fmt"
"github.com/pkg/errors"
)
type ValidationError struct {
Field string
Message string
}
func (e ValidationError) Error() string {
return fmt.Sprintf("validation error on %s: %s", e.Field, e.Message)
}
func validateInput(input string) error {
if len(input) < 5 {
return ValidationError{
Field: "input",
Message: "too short, minimum 5 characters",
}
}
return nil
}
func processInput(input string) error {
err := validateInput(input)
if err != nil {
return errors.Wrap(err, "input validation failed")
}
return nil
}
func main() {
err := processInput("abc")
var valErr ValidationError
if errors.As(err, &valErr) {
fmt.Printf("Validation error: %v\n", valErr)
fmt.Printf("Field: %s, Message: %s\n", valErr.Field, valErr.Message)
}
}
最佳实践
- 使用errors.Wrap在错误链中添加上下文信息
- 使用errors.Is检查特定错误
- 使用errors.As提取特定错误类型
- 在应用边界记录错误(如HTTP handler、main函数等)
- 避免过度包装错误,保持错误链简洁
package main
import (
"fmt"
"github.com/pkg/errors"
)
func databaseQuery() error {
return errors.New("connection timeout")
}
func businessLogic() error {
err := databaseQuery()
if err != nil {
return errors.Wrap(err, "failed to execute query")
}
return nil
}
func apiHandler() error {
err := businessLogic()
if err != nil {
// 在应用边界记录完整堆栈
fmt.Printf("API error: %+v\n", err)
return errors.New("internal server error") // 对客户端隐藏细节
}
return nil
}
func main() {
err := apiHandler()
if err != nil {
fmt.Println("Client error:", err)
}
}
通过合理使用这些技术,你可以构建健壮且易于调试的错误处理系统。pkg/errors
库特别适合需要错误堆栈跟踪和错误分类的中大型项目。