Error Type
errorString
Errors are an important part of the new logic and system stability in programs.
Built-in errors in go language are as follows:
// The error built-in interface type is the conventional interface for// representing an error condition, with the nil value representing no error interface { Error() string}
error
Type is an interface type, including oneError
method. It is the wrong top-level interface, and the structures that implement this built-in method are all subclasses of it.
errorString
The structure is a built-in implementation of the error interface built-in, the source code is as follows:
// New returns an error that formats as the given text. // Each call to New returns a distinct error value even if the text is identical. func New(text string) error { return &errorString{text} } // errorString is a trivial implementation of error. type errorString struct { s string } func (e *errorString) Error() string { return }
New
The method is built-in error type implementation.
() is the most commonly used error class implementation method.
wrapError
wrapError
is another implementation class of error, located infmt
The source code in the package is as follows:
// Errorf formats according to a format specifier and returns the string as a // value that satisfies error. // // If the format specifier includes a %w verb with an error operand, // the returned error will implement an Unwrap method returning the operand. // If there is more than one %w verb, the returned error will implement an // Unwrap method returning a []error containing all the %w operands in the // order they appear in the arguments. // It is invalid to supply the %w verb with an operand that does not implement // the error interface. The %w verb is otherwise a synonym for %v. func Errorf(format string, a ...any) error { p := newPrinter() = true (format, a) s := string() var err error switch len() { case 0: err = (s) case 1: w := &wrapError{msg: s} , _ = a[[0]].(error) err = w default: if { () } var errs []error for i, argNum := range { if i > 0 && [i-1] == argNum { continue } if e, ok := a[argNum].(error); ok { errs = append(errs, e) } } err = &wrapErrors{s, errs} } () return err } type wrapError struct { msg string err error } func (e *wrapError) Error() string { return } func (e *wrapError) Unwrap() error { return }
wrapError
is another built-in error implementation class, using%w
As a placeholder, wrapError here is implementedUnwrap
Method, the user returns the built-in err, that is, the nested err.
wrapError also has a plural formwrapErrors
I won't go into details here.
- Custom errors
Implementing custom errors is very simple. Implementing the error interface erros with object-oriented features is to implement the error class. Install the inherited features of the Go language and implement the corresponding methods of the interface.
type error interface { Error() string }
type MyErr struct { e string } func (s *MyErr) Error() string { return } func main(){ var testErr error testErr = &MyErr{"err"} (()) }
The above code implements a custom error type. Note that it is a structure, but it is actuallyerrorString
subclass of .
New error
The previous section introduces three error types. The first two are built-in error types, among which the customized errors are expandable and can implement any of the first two.
The first typeerrorString
It is relatively convenient to implement, onlyError()
method;
The second type iswrapError
Two methods are needed, and one isUnwrap()
。
()
err := ("this is a error") ("----%T----%v\n", err, err)
This method createserrorString
Class instance
()
err = ("err is: %v", "no found") (err)
This method createswrapError
Class instance, wrapError is also a subclass of errorString.
Instantiation
type MyErr struct { e string } func (s *MyErr) Error() string { return } func main(){ var testErr error testErr = &MyErr{"err"} (()) }
Since custom errors generally require error information, the instantiation of the method is generally constructed directly.
Error parsing
()
Used to determine whether one error is equal to another specific error. It not only simply compares the wrong values, it also checks all errors in the error chain to see if they match the given target error.
package main import ( "errors" "fmt" ) var ErrNotFound = ("not found") func findItem(id int) error { if id == 0 { return ErrNotFound } return nil } func main() { err := findItem(0) if (err, ErrNotFound) { ("Item not found") } else { ("Item found") } }
Note that there is a pit here, which is the type of error and error information judged by the Is method. Using the New method, even if the error information is the same and different, it is not equal, as follows:
err1 := ("err1") err2 := ("err1") err := (err1, err2) (err) // Output: false
()
Used to convert an error to a specific error type. If an error in the error chain matches the given target type, the error is converted to that type and assigned to the target variable.
package main import ( "errors" "fmt" ) type MyError struct { Code int Msg string } func (e *MyError) Error() string { return ("code %d: %s", , ) } func doSomething() error { return &MyError{Code: 404, Msg: "Not Found"} } func main() { err := doSomething() var myErr *MyError if (err, &myErr) { ("Custom error: %v (Code: %d)\n", , ) } else { ("Unknown error") } }
Can be used as type judgment.
()
()
is a function for handling nested or wrapped errors. Its main purpose is to extract and return an error direct underlying error (i.e., a wrapped error). If the error has not been wrapped, it will returnnil
。
package main import ( "errors" "fmt" ) func main() { baseErr := ("base error") wrappedErr := ("wrapped error: %w", baseErr) // Use to extract the underlying error unwrappedErr := (wrappedErr) ("Wrapped error:", wrappedErr) ("Unwrapped error:", unwrappedErr) } // Output Wrapped error: wrapped error: base error Unwrapped error: base error
This method can only obtain direct embedded errors for errors, and it is necessary to make easy judgments if you want to obtain deeper errors.
Notice:
-
: Used to determine whether an error is equal to a specific error value. Suitable for finding a specific error in the error chain (such as a known predefined error).
-
: Used to convert errors to specific error types. Suitable for use when you need to handle errors based on the specific type of error.
-
()
Used to extract from a wrapper error and return the underlying error. If the error has not been wrapped (or the Unwrap method is not implemented), it will returnnil
。
Error handling
if err := findAll(); err != nil { // logic }
Is this process very familiar?Error parsingThe processing method of subsections can perform subsequent processing of error judgments.
Go language also provides error capturerecover
Mechanism and error throwingpanic
mechanism.
panic
panic
It is a way to trigger exception handling mechanism in Go language. When you call panic, the program will immediately stop executing the current function and throw it up layer by layer from the call stack until a suitable recovery is found, or it will eventually cause the program to crash.
package main import "fmt" func main() { ("Start") panic("Something went wrong!") ("End") // This line will not be executed }
When called in the program panic
, the program will immediately abort the current control flow and start backtrackingStack
frames and execute each layer ofdefer
Statement. After executing all defer statements, if norecover
, the program will crash and print panic information and stack trace.
recover
recover
is a built-in function to restore panic. It can only bedefer
Valid in the function. When panic occurs, ifCurrent function
orAny call stack
The defer function in the function on it calls recovery, so the content of panic can be captured and the program can be restored to normal execution.
package main import "fmt" func main() { defer func() { if r := recover(); r != nil { ("Recovered from:", r) } }() ("Start") panic("Something went wrong!") ("End") // This line will not be executed }
Recover is usually used to ensure that some blocks of code can perform resource cleanup operations even if panic occurs and avoid the entire program crash.
defer
defer
Statements are used to delay the execution of functions and will not be executed until the function containing the defer statement has been executed. This is usually used to ensure that resource release or cleaning operations (such as closing files, unlocking mutexes, etc.) are performed even when an error occurs in the function or returns early.
- Execution order: In a function, you can have multiple defer statements. The order of execution of these defer calls is the last-in-first-out (LIFO). That is, the last defer statement will be executed first.
- Capture valueThe defer statement captures the value of the variable it references when declared. That is, the parameters in the defer statement are calculated when defer is declared, not when defer is executed.
The combination of three functions constitutes an error handling, as follows:
package main import "fmt" func main() { defer func() { if r := recover(); r != nil { ("Recovered from panic:", r) } }() ("Starting the program") causePanic() ("Program ended gracefully") } func causePanic() { ("About to cause panic") panic("A severe error occurred") ("This line will not execute") }
Starting the program About to cause panic Recovered from panic: A severe error occurred
Summarize
The above is personal experience. I hope you can give you a reference and I hope you can support me more.