Reread exception handling in Golang

Keywords: Operation & Maintenance Fragment

Review the exception handling in Golang together.

  • 1. There are no try...catch... Statements in other languages in golang to catch exceptions and recover exceptions.
  • 2. In Golang, we usually use the panic keyword to throw exceptions. In defer, we use recover to catch exceptions for specific logical processing.
  • 3. In golang, we usually return the error structure object in the function or method to determine whether there is an exception.

Matters needing attention

  • 1. With recover and panic instructions, defer must be defined before panic (panic will terminate the code to be executed later).
  • 2.recover is only valid in the function called by defer, otherwise recover cannot capture panic.
  • 3. After recover handles the exception, the business logic will run to the processing fragment after defer.
  • 4. Multiple defer will form a defer stack
  • 5.panic will wait until the whole goroutine exits to report the error.

Conventional use

  1. panic and recover parameter type are null interface (can store any type of object) interface {}
/*
func panic(v interface{})
func recover() interface{}
Execution order: panic() - > defer with recover
 Output results:
oh my god!panic.
Interpretation:
defer recover in successfully caught the panic exception
*/

package main
import (
    "fmt"
)
func main() {
    defer func() {
        if err := recover(); err != nil {
            fmt.Println(err)
        }
    }()
    panic("oh my god!panic.")
}
  1. Errors raised in a deferred call can be caught by subsequent deferred calls (only the last error is caught)
/*
//Execution order: panic() - > defer anonymous function with panic - > defer anonymous function with recover().
//Output results:
catch the panic
//Interpretation:
defer Medium recover Only the last error can be caught
package main
import (
    "fmt"
)
func main() {
    defer func() {
        if err := recover();err != nil {
            fmt.Println("catch the panic")
        }
    }()
    defer func() {
        panic("oh my god! panic.")
    }()

    panic("something panic!")

}

  1. The capture function recover() will terminate only if it is called directly within the defer call, otherwise nil will be returned.
/*
Code execution sequence: panic-> nested recover's defer function in an anonymous function > defer-> with recover of fmt, calling recover defer in anonymous function.
Output results:
defer inner
<nil>
defer recover panic error
 Explanation: a defer stack is formed between multiple defers, and the lowest defer takes precedence; the third defer prints the zero value 'nil' of recover(), and only the first defer successfully captures the lowest panic("panic error").
*/
package main
import "fmt"
func main() {
    defer func() {
        fmt.Println("defer recover",recover())
    }()
    defer recover()
    defer fmt.Println(recover())
    defer func() {
        func(){
            fmt.Println("defer inner")
            recover()
        }()
    }()
    panic("panic error")
}
  1. Placing code blocks in anonymous functions can realize exception recovery in function logic without affecting the main function
/*
Code execution order: panic statement in anonymous function - > i self addition operation in anonymous function - > fmt in anonymous function - > defer in anonymous function - > fmt in main function
 Output results:
i is: 2
 Explanation: panic will terminate its subsequent execution, so the priority of executing panic in anonymous function will be captured by recover in defer, i will be assigned as 2, then anonymous function exits and continues to execute fmt.Println statement in main function.
*/
package main
import "fmt"
func main() {
    test()
}
func test() {
    var i int
    func() {
        defer func(){
            if err := recover();err != nil {
                i = 2
            }
        }()
        panic("something panic!")
        i += 8
        fmt.Println("no panic, i is:",i)
    }()
    fmt.Println("i is:",i)
}
  1. recover in goroutine

Note: if a goroutine without recover has panic, the whole process will be suspended.

/*
sync.WaitGroup It is used to Wait for the end of a group of goroutines. The Add method is used to set the number of goroutines to Wait. The Done method indicates the end of a goroutine operation. The Wait method is used to block all goroutines until all goroutines are executed.

Code execution order: Logic in goroutine - > WG. Wait() - > FMT. Println
 Output results:
panic recover assignment to entry in nil map
donw
 Interpretation:
In goroutine, we declare a map[string]string type of info. We all know that map, slice and channel are all reference types. We need to use the make function to initialize and assign values. In this case, using info ["name"] = "bgbio" to assign values directly will cause panic, fmt.Println function to be terminated, thus executing defer with recover, then executing defer with wg.Done() and exiting goroutine to execute main program logic.
*/
package main
import (
    "fmt"
    "sync"
)
func main() {
    var wg sync.WaitGroup
    wg.Add(4)
    go func() {
        defer wg.Done()
        defer func() {
            if err := recover();err != nil {
                fmt.Println("panic recover",err)
            }
        }()
        var info map[string]string
        info["name"] = "BGBiao"
        fmt.Println(info)
    }()
    wg.Wait()
    fmt.Println("done")
}

Welcome to my public ID: bgbio, make progress together~

Posted by paulg on Sun, 20 Oct 2019 07:01:04 -0700