Introduction
The go language pursues simplicity, so there is no try…catch statement in the go language. Because the author of the go language believes that mixing exceptions and control statements can easily make this program confused, and exceptions can easily be abused. So in the go language, in order to prevent exceptions from being abused. We often use the return value of a function to return an error, rather than using exceptions instead of errors. If you really need to handle exceptions in some scenarios, you can use panic and recover. panic is used to throw exceptions, recover is used to recover exceptions.
panic is a function used in Go language to terminate a program, which is often used in the following two situations: 1) The program has a large failure, such as the service cannot be provided. 2) The program encounters memory exceptions during the run phase, such as taking the value of a null pointer, rewriting read-only memory, etc. For panic, 1) Scenarios are often called actively; 2) Scenarios are called passively. Once panic is generated, they will dump the data in the stack, which makes it convenient for developers to locate problems. Recover is used to intercept panic exception information. After intercepting, the program can be controlled to skip panic and continue to execute.
Need to note:
- panic can change the control flow of the program. After calling panic, it will immediately stop executing the remaining code of the current function, and recursively execute the caller's defer in the current Goroutine;
- recover can abort program crashes caused by panic. It is a function that can only work in defer, and calls in other scopes will not work;
1. Features
- panic will only trigger the defer of the current goroutine
- revoce can only take effect if it is called in defer
- panic allows nested multi-magnetic calls in defer
Trigger process
- 1. If a panic statement is written and triggered in function F, the code to be executed will be terminated. If there is a list of defer functions to be executed in the function F where panic is located, it will be executed in reverse order in the order of defer writing;
- 2. If function G calls function F, then function F panic returns the caller function G. In function G, statements after calling function F statement will not be executed. If there is also a list of defer functions to be executed in function G, then the reverse order of the defer writing order is OK;
- Exit the entire goroutine and report an error.
Key points for use
- The purpose of recover is to capture panic, thereby restoring normal code execution;
- Recover must be used with defer;
- Recover does not have incoming parameters, but there is a return value. The return value is the value passed by panic
4. Usage scenarios
Generally, there are two situations to use:
- When the program encounters an error that cannot be executed, an error will be thrown and the run will be terminated automatically.
- When debugging the program, print the stack through panic to facilitate positioning errors.
1. Practice
1. Cross-thread failure
package main import ( "fmt" "time" ) func main() { // The defer function in the main thread will not be executed, because after the child coroutine panic, the defer in the main thread will not be executed defer println("in main") go func() { defer println("in goroutine") ("Subcorrelation running") panic("Subcord crash") }() (1 * ) }
#Output$ go run Subcorrelationsrunning in goroutine panic: Subcorrelations崩溃 goroutine 6 [running]: .func1()
When running this code, you will find that the defer statement in the main function is not executed, and only the defer in the current Goroutine is executed.
2. Recover that does not work
Beginners of Go language engineers may write the following code and call recover in the main program to attempt to abort the program's crash, but it can also be seen from the running results that the following program does not exit normally.
package main import "fmt" func main() { defer ("in main") if err := recover(); err != nil { (err) } panic("unknown err") }
#Output$ go run in main panic: unknown err goroutine 1 [running]: () D:/gopath/src/Go_base/lesson/panic/:11 +0x125
A careful analysis of this process allows you to understand the reason behind this phenomenon. Recover will only take effect after panic occurs. However, in the above control flow, recover is called before panic and does not meet the conditions for taking effect, so we need to use the recover keyword in defer.
The correct way to write it should be like this:
package main import "fmt" func main() { defer ("in main") defer func() { if err := recover(); err != nil { ("occur error") (err) } }() panic("unknown err") }
3. Nested panic
panic can be called nested multiple times. , the following code shows how to call panic multiple times in the defer function:
package main import "fmt" func main() { defer ("in main") defer func() { defer func() { panic("panic again and again") }() panic("panic again") }() panic("panic once") }
#Output$ go run in main panic: panic once panic: panic again panic: panic again and again goroutine 1 [running]: .func1.1()
From the results output from the above program, we can confirm that the program calls panic multiple times will not affect the normal execution of the defer function, so it is generally safe to use defer for finishing work.
4. Things to note
grammar
//The following capture faileddefer recover() defer (recover) defer func(){ func(){ recover() //Invalid, nesting two layers }() }() //The following capture is validdefer func(){ recover() }() func except(){ recover() } func test(){ defer except() panic("runtime error") }
2. Multiple panics will only capture the last one
package main import "fmt" func main(){ defer func(){ if err := recover() ; err != nil { (err) } }() defer func(){ panic("three") }() defer func(){ panic("two") }() panic("one") }
summary
This is the end of this article about the introduction and practice of panic / recovery in Go. For more related go panic / recovery, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!