In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-22 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article mainly introduces "how to deal with Go program errors". In daily operation, I believe many people have doubts about how to deal with Go program errors. The editor consulted all kinds of materials and sorted out simple and easy-to-use operation methods. I hope it will be helpful to answer the doubts about "how to deal with Go program errors". Next, please follow the editor to study!
Catalogue
Preface
Get to know error
Custom error remember to implement the error interface
To deal with common mistakes.
Two common problems in mishandling
Attach context information to the error
Summary
Preface
The error handling of Go is often complained about by everyone every day. I have also observed some phenomena in my work, and what is more serious is that there is some repetition of error handling in all levels of logic code.
For example, someone writing code will judge errors and log at each layer, which seems rigorous from the code level, but if you look at the log, you will find a pile of repetitive information, which will cause interference when troubleshooting the problem.
Today, I would like to summarize three best practices related to error handling in Go code.
These best practices are also shared by some of my predecessors on the Internet. After my own practice, I describe them in my own language here, hoping to be helpful to all of you.
Get to know error
The Go program represents an error by a value of type error
The error type is a built-in interface type that specifies only one Error method that returns a string value.
Type error interface {Error () string}
Functions in the Go language often return an error value, and the caller handles the error by testing whether the error value is nil.
I, err: = strconv.Atoi ("42") if err! = nil {fmt.Printf ("couldn't convert number:% v\ n", err) return} fmt.Println ("Converted integer:", I)
An error of nil indicates success; a non-nil error indicates failure.
Custom error remember to implement the error interface
We often define error types that meet our needs, but remember to have these types implement the error interface so that you don't have to introduce additional types into the caller's program.
For example, we define the type myError ourselves. If we do not implement the error interface, the caller's code will be invaded by the type myError. For example, the following run function can be directly defined as error when defining the return value type.
Package myerrorimport ("fmt"time") type myError struct {Code int When time.Time What string} func (e * myError) Error () string {return fmt.Sprintf ("at% v,% s, code% d", e.When, e.What, e.Code)} func run () error {return & MyError {1002, time.Now (), "it didn't work",}} func TryIt () {if err: = run () Err! = nil {fmt.Println (err)}}
If myError does not implement the error interface, the return type here will be defined as the myError type. It is conceivable that the caller's program will then use myError.Code = = xxx to determine what kind of specific error it is (of course, if you want to do this, you have to change the myError to the exported MyError).
What should the caller do when determining which kind of error the custom error is? the myError is not exposed to the package, but the answer is to check for error behavior by exposing it outside the package.
Myerror.IsXXXError (err)...
Or it can be judged by comparing whether the error itself is equal to the constant errors exposed by the package, such as io.EOF, which is often used to manipulate a file to determine whether the file is finished.
Similarly, there are error constants exposed by various open source packages such as gorm.ErrRecordNotFound.
If err! = io.EOF {return err} error handling common mistakes
Let's take a look at a simple program to see if you can find some minor problems.
Func WriteAll (w io.Writer, buf [] byte) error {_, err: = w.Write (buf) if err! = nil {log.Println ("unable to write:", err) / / annotated error goes to log file return err / / unannotated error returned to caller} return nil} func WriteConfig (w io.Writer, conf * Config) error {buf Err: = json.Marshal (conf) if err! = nil {log.Printf ("could not marshal config:% v", err) return err} if err: = WriteAll (w, buf) Err! = nil {log.Println ("could not write config:% v", err) return err} return nil} func main () {err: = WriteConfig (f, & conf) fmt.Println (err) / / io.EOF} two common problems in error handling
The error handling of the above program exposes two problems:
1. After the error occurred in the underlying function WriteAll, in addition to returning the error to the upper layer, the upper caller did the same thing, recorded the log and then returned the error to the top level of the program.
So get a bunch of duplicates in the log file.
Unable to write: io.EOF
Could not write config: io.EOF
...
two。 At the top of the program, although the original error is obtained, there is no relevant content, in other words, the information recorded in log by WriteAll and WriteConfig is not packaged into the error and returned to the upper layer.
The solution to these two problems may be to add context information to the errors in the underlying functions WriteAll and WriteConfig, and then return the errors to the upper layer, and the upper layer program will finally deal with these errors.
A simple way to wrap an error is to use the fmt.Errorf function to add information to the error.
Func WriteConfig (w io.Writer, conf * Config) error {buf, err: = json.Marshal (conf) if err! = nil {return fmt.Errorf ("could not marshal config:% v", err)} if err: = WriteAll (w, buf) Err! = nil {return fmt.Errorf ("could not write config:% v", err)} return nil} func WriteAll (w io.Writer, buf [] byte) error {_, err: = w.Write (buf) if err! = nil {return fmt.Errorf ("write failed:% v", err)} return nil} attach context information to the error
Fmt.Errorf just adds a simple comment message to the error. If you want to add the wrong call stack along with the information, you can take advantage of the error wrapper provided by the github.com/pkg/errors package.
/ / append only new information func WithMessage (err error, message string) error// only call stack information func WithStack (err error) error// and stack and information func Wrap (err error, message string) error
If there is a wrapper method, there is a corresponding unpacking method, and the Cause method returns the original error corresponding to the wrapper error-- that is, it unwraps it recursively.
Func Cause (err error) error
The following is the error handler after rewriting using github.com/pkg/errors
Func ReadFile (path string) ([] byte, error) {f, err: = os.Open (path) if err! = nil {return nil, errors.Wrap (err, "open failed")} defer f.Close () buf, err: = ioutil.ReadAll (f) if err! = nil {return nil, errors.Wrap (err, "read failed")} return buf, nil} func ReadConfig () Error) {home: = os.Getenv ("HOME") config, err: = ReadFile (filepath.Join (home, ".settings.xml") return config, errors.WithMessage (err, "could not read config")} func main () {_, err: = ReadConfig () if err! = nil {fmt.Printf ("original error:% T% v\ n", errors.Cause (err) Errors.Cause (err)) fmt.Printf ("stack trace:\ n% roomv\ n", err) os.Exit (1)}
The% + v used to format the string above expands the value on the basis of% v, that is, to expand the compound type value, such as the details such as the field value of the structure.
In this way, you can not only add call stack information to the error, but also retain the reference to the original error, and through Cause you can revert to the cause of the original error.
At this point, the study on "how to deal with Go program errors" is over. I hope to be able to solve your doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.