Basics
Error handling should be part of the project. The error in Golang is an interface
type, as follows:
type error interface { Error() string }
Any structure that implements the Error()
method can be treated as an error. Therefore, if an error may occur in the function, you can return an error at the end of the return value, for example:
func foo() error { // ... do something return errors.New("foo error") }
Return the error directly
Return the error directly, similar to directly Returns an error of string type, or an error code or the like. String type errors were mentioned in the Basics section. The error code is equivalent to the error code in Linux and C programming. Generally, we need to define it ourselves. For example:
package mypkg type ErrCode int const ( ERR1 = 1 ERR2 = 2 ERR3 = 3 ) func sub(a, b int) (int, ErrCode) { if b < 0 { return 0, ERR1 } else if a < b { return 0, Err2 } else if a < 0 { return 0, Err3 } return a - b }
This type of error is simple to write, but it has two flaws:
1. If you want to use error codes in the outer layer, you need to introduce this package, which is easy A circular reference occurs.
2. If the error code type returned is modified internally in the package, corresponding modifications must be made wherever the error code is used externally, destroying the closure.
For the first flaw, you can use a third-party package to specifically store error codes. This method is worthy of discussion. Never judge the value of the string returned by the Error() method to handle the corresponding error! ! !
Return a custom type of error
This method can return a custom type and perform related error handling by asserting the custom type; custom type It can carry more information. Code example:
package main import ( "errors" "fmt" "runtime/debug" ) type MyError struct { Inner error // 内粗错误 Message string // 自定义错误信息 StackTrace string // 堆栈信息 Misc map[string]interface{} //其它的一些数据 } func (myError MyError) Error() string { return myError.Message } func wrapError(err error, msg string, msgArgs ...interface{}) MyError { return MyError{ Inner: err, Message: fmt.Sprintf(msg, msgArgs), StackTrace: string(debug.Stack()), Misc: make(map[string]interface{}), } } func Handle(key int) error { if key < 0 { return wrapError(errors.New("key < 0"), "This is an error test") } return nil } func main() { if err := Handle(-1); err != nil { if e, ok := err.(MyError); ok { fmt.Printf("Inner: %v, Message: %v, StackTrace: %v\n", e.Inner, e.Message, e.StackTrace) // 这里输出对应的数据 } } }
This way of handling the problem is more convenient, but there may still be problems with package circular references.
Error handling to hide internal details
The above two methods can be adapted to some scenarios, but neither can solve the problem of possible circular dependencies. To this end, we use the github.com/pkg/errors
package to solve the problem and give a code example.
func New(message string) error
If there is a ready-made error, we need to package it again. At this time, there are three functions to choose from.
//只附加新的信息 func WithMessage(err error, message string) error //只附加调用堆栈信息 func WithStack(err error) error //同时附加堆栈和信息 func Wrap(err error, message string) error
In fact, the above packaging is very similar to Java's exception packaging. The packaged error is actually Cause. The root cause of the error mentioned in the previous chapter is this Cause. So this error handling library provides us with the Cause function so that we can get the most fundamental cause of the error.
func Cause(err error) error { type causer interface { Cause() error } for err != nil { cause, ok := err.(causer) if !ok { break } err = cause.Cause() } return err }
Use a for loop to find the most fundamental (bottom-level) error.
Recommended related articles and tutorials: golang tutorial
The above is the detailed content of Detailed introduction to the error handling mechanism in golang. For more information, please follow other related articles on the PHP Chinese website!