An error indicates that an abnormal condition has occurred in the program. The Go language provides a very simple error handling mechanism through the built-in error interface.
• The error type is a built-in type of the go language. When using it, it is not necessary to import it because it is essentially an interface
The error type is an interface type, and this is its definition:
1type error interface {
2 Error() string
3}
An example to understand error
1package main
2import (
3 "fmt"
4 "os"
5)
6func main() {
7 //Attempting to open a file that does not exist will return an error
8 f, err := os.Open("/test.txt")
9 if err != nil {
10 fmt.Println(err) //no such file or directory
11 return
12 }
13 fmt.Println(f.Name(), "opened successfully")
14}
The idiomatic way to handle errors in go is to compare the returned error to nil. A zero value indicates that no error occurred, while a non-zero value indicates that there was an error.
Customization
You can see above that error has a method signed Error() string. All types that implement this interface can be treated as an error type.
Order errors via the errors package
Function prototype:func New(text string) error Creating an error using a string can be thought of as New(fmt.Sprintf(...)) .
1import "errors" //To use errors you must import the "errors" package
2error := errors.New("Myerror")
3if error != nil {
4 fmt.Print(err) //Myerror
5}
demo
1package main
2import (
3 "errors"
4 "fmt"
5 "math"
6)
7func circleArea(radius float64) (float64, error) {
8 if radius < 0 {
9 //Create an error using a string
10 return 0, errors.New("Area calculation failed, radius is less than zero")
11 }
12 return math.Pi * radius * radius, nil
13}
14func main() {
15 radius := -20.0
16 area, err := circleArea(radius)
17 if err != nil {
18 fmt.Println(err)
19 return
20 }
21 fmt.Printf("Area of circle %0.2f", area)
22}
Go through fmt.Errorf() to order
Function prototype:func Errorf(format string, a . . interface{}) error Errorf generates a format string based on the format parameter and returns an error containing that string.
1err := fmt.Errorf("error")
2if err != nil {
3 fmt.Print(err)
4}
1return 0, fmt.Errorf("Area calculation failed, radius %.2f is less than zero",radius)
Use structures and fields to customize
1type MyError struct {
2err error
3}
4//Error()
5func (e MyError) Error() string {
6 return e.err.Error()
7}
8func main() {
9 err:=MyError{
10 errors.New("error"),
11 }
12 fmt.Println(err.Error())
13}
demo
1package main
2import (
3 "fmt"
4 "math"
5
6)
7type areaError struct {
8 err string
9 radius float64
10}
11func (e *areaError) Error() string {
12 return fmt.Sprintf("radius %0.2f:%s", e.radius, e.err)
13}
14
15func (e *areaError) IsRadiusNagative() bool {
16 return e.radius < 0
17
18}
19func circleArea(radius float64) (float64, error) {
20 if radius < 0 {
21 return 0, &areaError{"Radius is negative", radius}
22 }
23 return math.Pi * radius * radius, nil
24}
25func main() {
26 s, err := circleArea(-20)
27 if err != nil {
28 //Converting errors to specific types
29 if err, ok := err.(*areaError); ok {
30 fmt.Printf("Radius %.2f is less than zero", err.radius)
31 return
32 }
33 fmt.Println(err)
34 return
35 }
36 fmt.Println(s)
37}
panic (throwing errors) and recover (catching errors)
There is no such exception catch statement as try...catch... in golang, but the panic and recover built-in functions are provided for throwing exceptions and catching exceptions.
• The parameter type of panic and recover is interface{}, so any type of object can be thrown. • If a fatal error occurs in the program and the entire program cannot proceed, golang provides the panic function to exit the program. • When a program panics, use recover to regain control of the program. • Not all panic exceptions come from the runtime, directly calling the built-in panic function will also raise a panic exception • The panic function accepts any value as a parameter. (1) Use of panic
Errors raised during a delayed call can be caught by subsequent delayed calls, but only the last error can be caught.
1func test() {
2defer func() {
3 fmt.Println(recover())
4}()
5defer func() {
6 panic("defer panic")
7}()
8 panic("test panic")
9}
10func main() {
11 test() //defer panic
12}
When a function panic occurs, it terminates, and after all the delayed functions are executed, program control returns to the the caller of that function. This process continues until all functions of the current concurrent process return and exit, then the program prints the panic message, followed by a stack trace, and finally the program terminates.
If the function is not panic, calling the recover function will not get any information and will not affect the current process.
demo
1package main
2import (
3 "fmt"
4)
5func fullName(firstName *string, lastName *string) {
6 if firstName == nil {
7 panic("Firsr Name can"t be null")
8 }
9 if lastName == nil {
10 panic("Last Name can"t be null")
11 }
12 fmt.Printf("%s %s\n", *firstName, *lastName)
13 fmt.Println("returned normally from fullName")
14}
15func test(){
16 defer fmt.Println("deferred call in test")
17 firName := "paul"
18 fullName(&firName, nil)
19}
20func main() {
21 defer fmt.Println("deferred call in main")
22 test()
23 fmt.Println("returned normally from main")
24}
output
Use of recover
If the goroutine is not panic, then calling the recover function will return nil. The recover function will only close errors if called directly within a delayed call, otherwise it will always return nil. Any uncaught errors will be passed out along the call stack.
Modify the above example to use recover to catch exceptions
1package main
2import (
3 "fmt"
4)
5func recoverName() {
6 if r := recover(); r != nil{
7 fmt.Println("recovered from ",r)
8 }
9}
10func fullName(firstName *string, lastName *string) {
11 defer recoverName()
12 if firstName == nil {
13 panic("Firsr Name can"t be null")
14 }
15 if lastName == nil {
16 panic("Last Name can"t be null")
17 }
18 fmt.Printf("%s %s\n", *firstName, *lastName)
19 fmt.Println("returned normally from fullName")
20}
21func test(){
22 defer fmt.Println("deferred call in test")
23 firName := "paul"
24 fullName(&firName, nil)
25}
26func main() {
27 defer fmt.Println("deferred call in main")
28 test()
29 fmt.Println("returned normally from main")
30}
The output is:
When a panic occurs, the current function uses recover, the error is caught, and the error is handed over to the upper-layer caller to execute the rest of the code normally; if the current function does not use recover and the caller uses recover, it belongs to the caller's capture If an error occurs, give the permission to the caller of the caller, and then execute normally.
recover function captures the error, but at this time we do not easily find the location of the error, then you can use debug.PrintStack() in the function that implements the recover function, so that you can output the function where the error occurs, using this the first line shown is the system, which is the specific location under the stack.go package, this will have Two lines, then the place where debug.PrintStack() is called, this is the function that you write, and then the system's panic.go package, because the time of the error will call the function inside this package, and then the specific location of the error.
Function prototype:func Stack() []byte Stack returns a formatted call stack trace of the go procedure. For each call stack, it includes the line information and PC value of the original file; for go functions it also tries to get the function or method that called the function, and the text of the line where the call was made. func PrintStack() PrintStack prints the Stack return information to the standard error output.
demo
1import (
2"fmt"
3"runtime/debug"
4)
5func r() {
6 if r := recover(); r != nil {
7 fmt.Println("Recovered", r)
8 debug.PrintStack()
9 }
10}