Delayed call
In Go, deferred calls are a very important feature, which allows you to arrange for a function to be executed after the current function is executed, regardless of whether panic occurs or not.
This is usually used for resource cleaning, file closing, unlocking mutex locks, etc.
1. Delayed call
defer
The statement will defer a function until it contains thedefer
The function of the statement is executed when it is about to return. The parameters of the function that is delayed execution will be evaluated immediately, but the function itself will be delayed until the peripheral function returns.
1.1 Use scenarios
- Resource Cleanup: Such as closing files, network connection, etc.
- Unlock mutex: After accessing shared resources, make sure the mutex is released.
- Print debugging information: Print some debug information or log at the end of the function.
1.2 Example
func DeferDemo() { num := 100 num += 200 // Delayed call // But the value of num is calculated by the function call position defer printMessage(num) num += 5 (num) } func printMessage(num int) { ("printMessage func") ("i am in defer: ", num) }
Test Method
func TestDeferDemo(t *) { DeferDemo() }
Output result
=== RUN TestDeferDemo
305
printMessage func
i am in defer: 300
--- PASS: TestDeferDemo (0.00s)
PASS
2. panic
panic
It is a built-in function. When an error that cannot be recovered during the program is run, it can be called.panic
function.
It will immediately interrupt the execution of the current function and start executing the registered delayed call layer by layer (defer
statement).
After the delayed call is executed, the program crashes and prints out and passes topanic
The value of the function.
2.1 Use scenarios
panic
It is usually used to deal with severe runtime errors, such as array out of bounds, null pointer references, etc.
2.2 Example
func panicDemo() { divide_func := func(a, b int) int { if b == 0 { panic("divide by zero") } return a / b } defer printMessage(1) divide_func(1, 0) ("Not executed") }
Test Method
func Test_panicDemo(t *) { panicDemo() }
Output result
=== RUN Test_panicDemo
printMessage func
i am in defer: 1
--- FAIL: Test_panicDemo (0.00s)
panic: divide by zero [recovered]
panic: divide by zerogoroutine 3 [running]:
.func1.2({0x1042b9dc0, 0x1042e3860})
……
3. recover
recover
is a built-in function that is used topanic
Recovery in the middle.
recover
It is only useful when called in a delayed call function.
Called in normal execution processrecover
Will returnnil
, and there will be no effect.
If it is called in a delayed call functionrecover
, and the function it is located in is due topanic
And exiting, thenrecover
Will be captured and passed topanic
value and prevents the program from crashing. At this time, the program will continue to executepanic
Code after click (if any).
3.1 Use scenarios
recover
Usually used in the event of potentialpanic
Additional error handling logic is added around the code block to allow the program to elegantly recover in the event of a serious error.
3.2 Example
func recoverDemo() { divideFunc := func(a, b int) int { if b == 0 { panic("divide by zero") } return a / b } saveDivideFunc := func() (int, error) { defer func() { // Capture any possible panic if r := recover(); r != nil { ("Recovered from panic:", r) } }() // Try to perform an operation that may trigger panic result := divideFunc(10, 0) // If no panic occurs, the result will be returned return result, nil } divideRes, err := saveDivideFunc() if err != nil { (err) } else { (divideRes) } }
Test Method
func Test_recoverDemo(t *) { recoverDemo() }
Output result
=== RUN Test_recoverDemo
Recovered from panic: divide by zero
0
--- PASS: Test_recoverDemo (0.00s)
PASS
Source code
// defer_demo.go filepackage function_demo import "fmt" func DeferDemo() { num := 100 num += 200 // Delayed call // But the value of num is calculated by the function call position defer printMessage(num) num += 5 (num) } func printMessage(num int) { ("printMessage func") ("i am in defer: ", num) } func panicDemo() { divideFunc := func(a, b int) int { if b == 0 { panic("divide by zero") } return a / b } defer printMessage(1) divideFunc(1, 0) ("Not executed") } func recoverDemo() { divideFunc := func(a, b int) int { if b == 0 { panic("divide by zero") } return a / b } saveDivideFunc := func() (int, error) { defer func() { // Capture any possible panic if r := recover(); r != nil { ("Recovered from panic:", r) } }() // Try to perform an operation that may trigger panic result := divideFunc(10, 0) // If no panic occurs, the result will be returned return result, nil } divideRes, err := saveDivideFunc() if err != nil { (err) } else { (divideRes) } }
package function_demo import "testing" func TestDeferDemo(t *) { DeferDemo() } func Test_panicDemo(t *) { panicDemo() } func Test_recoverDemo(t *) { recoverDemo() }
This is the end of this article about Golang's project practice to implement delayed calls. For more related Golang's delayed calls, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!