SoFunction
Updated on 2025-03-04

Detailed explanation of the use of defer, panic, and recover of Golang exception handling

What is delay

defer is a delay statement. In rare cases, Go uses defer, panic, and recover as exception handling forms.

defer can delay functions, delay methods, delay parameters.

Delay function

You can add multiple defer statements to the function.

When the function is executed to the end, these defer statements will be executed in reverse order, and the function will finally return. Especially when you are performing some operations to open resources, you need to return in advance when you encounter an error, and you need to close it before returning.

The corresponding resources may easily cause resource leakage and other problems.

If there are many calls to defer, then defer adopts the last-in first-out mode

Execute when leaving the method (and also execute when an error is reported)

Example Code 1:

package main
import "fmt"
func main() {
 defer funA()
 funB()
 funC()
 ("main...over....") }
func funA() {
 ("I amfunA()...") }
func funB() { //
 ("I amfunB()...") }
func funC() {
 ("I amfunC()。。") }

Running results:

I'm funB()...
I'm funC(). .
main...over....
I'm funA()...

Example Code 2:

package main
import "fmt"
func main() {
 s1 := []int{78, 109, 2, 563, 300}
 largest(s1) }
func finished() {
 ("Finish!") }
func largest(s []int) {
 defer finished()
 ("Start searching for maximum number...")
 max := s[0]
 for _, v := range s {
 if v > max {
 max = v
 }
 }
 ("The maximum number in %v is: %v \n", s , max) }

Running results:

Start looking for the maximum number...
The maximum number in [78 109 2 563 300] is: 563
Finish!

Delay method

Delay is not limited to functions. It is also completely legal to delay a method call.

Sample code:

package main
import "fmt"
type person struct {
 firstName string
 lastName string
}
func (p person) fullName() {
 ("%s %s", , ) }
func main() {
 p := person{"Steven", "Wang"}
 defer ()
 ("Welcome ") }

Running results:

Welcome Steven Wang

Delay parameters

The parameters of the delay function are executed when the delay statement is executed, not when the actual function call is executed.

Sample code:

package main
import "fmt"
func printAdd(a , b int) {
 ("In the delay function: the parameters a and b are %d and %d respectively, and the sum of the two numbers is: %d\n",
a , b , a+b) }
func main() {
 a := 5
 b := 6
 //The parameters of the delay function are executed when the delay statement is executed, rather than executing the actual function call.⽤Time-handed⾏。
 defer printAdd(a , b)
 a = 10
 b = 7
 ("Before the delay function is executed, the parameters a and b are %d and %d respectively, and the sum of the two numbers is:
 %d\n", a , b , a+b) }

Running results:

Before the delay function is executed: the parameters a and b are 10 and 7 respectively, and the sum of the two numbers is: 17
In the delay function: the parameters a and b are 5 and 6 respectively, and the sum of the two numbers is: 11

Delay of stack

When a function has multiple delayed calls, they are added to a stack and executed in the last In First Out (LIFO) order.

Sample code: Use defer to implement string inversion

package main
import "fmt"
func main() {
 name := "StevenWang welcomes learning blockchain"
 ("Raw String: %s\n", name)
 ("Flipped string: ")
 ReverseString(name) }
func ReverseString(str string) {
 for _, v := range []rune(str) {
 defer ("%c", v)
 }
}

Return result:

Original string: StevenWang welcomes learning blockchain
Flipped string:
Welcome to study and study in blockchain

Delayed applications

So far, the sample code we wrote has no practical application. Now take a look at the application about delay. Delays are executed without considering the code flow. Let's understand this problem with a program example using WaitGroup. We will write the program first without using delay, then we will modify it to use delay and understand how useful the delay is.

Sample code:

package main
import (
 "fmt"
 "sync"
)
type rect struct {
 length int
 width int
}
func (r rect) area(wg *) {
 if  < 0 {
 ("rect %v's length should be greater than zero\n", r)
 ()
 return
 }
 if  < 0 {
 ("rect %v's width should be greater than zero\n", r)
 ()
 return
 }
 area :=  * 
 ("rect %v's area %d\n", r, area)
 ()
}
func main() {
 var wg 
 r1 := rect{-67, 89}
 r2 := rect{5, -67}
 r3 := rect{8, 9}
 rects := []rect{r1, r2, r3}
 for _, v := range rects {
 (1)
 go (&wg)
 }
 ()
 ("All go routines finished executing")
}

Modify the above code:

package main
import (
 "fmt"
 "sync"
)
type rect struct {
 length int
 width int
}
func (r rect) area(wg *) {
 defer ()
 if  < 0 {
 ("rect %v's length should be greater than zero\n", r)
 return
 }
 if  < 0 {
 ("rect %v's width should be greater than zero\n", r)
 return
 }
 area :=  * 
 ("rect %v's area %d\n", r, area) }
func main() {
 var wg 
 r1 := rect{-67, 89}
 r2 := rect{5, -67}
 r3 := rect{8, 9}
 rects := []rect{r1, r2, r3}
 for _, v := range rects {
 (1)
 go (&wg)
 }
 ()
 ("All go routines finished executing")
}

Program running results:

rect {8 9}'s area 72
rect {-67 89}'s length should be greater than zero
rect {5 -67}'s width should be greater than zero
All go routines finished executing

panic and recover (downtime and downtime recovery)

panic and recover mechanisms

1. Overview:

panic: The meaning of the word "panic", recover: "recover"

Go language pursues simplicity and elegance. Go does not have the try…catch…finally exception handling mechanism like Java. Go designers believe that mixing exceptions with process control can make the code messy.

In Go, use multiple values ​​to return to errors. No exceptions are used to replace errors, nor do exceptions be used to control the process.

The go language uses panic() and recover() to implement extremely special exception handling in the program. In other words, in a very rare case, Go uses defer, panic, and recover as exception handling forms.

  • panic() lets the current program panic and interrupts the execution of the program. In other words, panic is a built-in function that can interrupt the original control process and enter a panic process.
  • When function F calls panic, the execution of function F is interrupted, but the delay function in F will execute normally, and F returns to where it is called. Where the call is called, F behaves like a panic is called. This process continues upward until all calls in the goroutine in the panic occur return, and the program exits.
  • Panic can be generated by calling panic directly. It can also be generated by runtime errors, such as accessing an out-of-bounds array.
  • recover is a built-in function that restores goroutines entering panic flows.
  • recover(), to restore the program, must be executed in the defer function. In other words, recover is only valid in delay functions.
  • During normal execution, calling recover will return nil and there is no other effect. If the current goroutine is in panic, calling recover can capture the input value of the panic and resume normal execution.

It is important to remember that it should be used as a last resort, that is, there should be no, or very few things like panic in our code.

Sample code

package main
import "fmt"
func main() {
 /*
  panic: the meaning of "panic",
  recover: "Recover"
  Go language uses panic() and recover() to implement extremely special exception handling in the program
  panic(), let the current program panic and interrupt the execution of the program
  recover(), to restore the program, must be executed in the defer function
  */
 funA()
 funB()
 funC()
 ("main...over....") }
func funA() {
 ("I'm a functionfunA()...") }
func funB() { //Peripheral functions defer func() {
 if msg := recover(); msg != nil {
 (msg, "Recovered....")
 }
 }()
 ("I'm a functionfunB()...")
 for i := 1; i &lt;= 10; i++ {
 ("i:", i)
 if i == 5 {
 //Let the program break panic("FunB function, panic....") //Offer the execution of the program.  . }
 }
 //When the code in the peripheral function causes a running panic, only after all the delay functions are executed, the operation is⾏Only when panic can it be truly expanded⾄Adjust⽤function。
}
func funC() {
 defer func() {
 ("Func's delay function....")
 //if msg := recover(); msg != nil {
 // (msg, "Recovered...") //}
 ("recover executed" , recover())
 }()
 ("I'm a functionfunC()。。")
 panic("FunC is panicking.") }

The above is the detailed explanation of the use of defer, panic, and recover in Golang exception handling. For more information about Golang defer panic recover, please follow my other related articles!