In Go, there are many process-control statements, such as if, else, and so on. These process-control keywords exist in other languages, but there are also a few special process-control keywords in Go, such as defer, panic, and recover.

1. defer

As defer guarantees that some code will be called before the function or method returns, even if the method does not finish properly and a panic occurs, the code following defer will execute. Note here that the function or method is not called before exiting a scope.

As defer is usually used to reclaim some resources, such as closing files, closing database connections, and releasing some resources (releasing locks). There are a few things to be aware of when using Defer.

  1. Parameter precalculation

When we define defer, the referenced external argument will be copied immediately, as determined before i++ executes, and the following code will print out the value 0 instead of 1:

func t1(a) {
	i := 0
	defer fmt.Println(i)
	i++
}
Copy the code

If you want the last printed value to be 1, make the following change:

func t2(a) {
	i := 0
	defer func(a) {
		fmt.Println(i)
	}()
	i++
}
Copy the code
  1. If more than one defer statement is defined, the last one is executed first

The following code outputs 4, 3, 2, 1:

func t3(a) {
	defer fmt.Println(1)
	defer fmt.Println(2)
	defer fmt.Println(3)
	defer fmt.Println(4)}Copy the code
  1. Defer assigns to the named return value of the method or function

In the code below, normally return 1, but use defer to continue assigning to the returned value, so the final return value is 2.

2. panic

Panic is a built-in function of Go that interrupts the normal flow of execution of the current code. If a panic occurs in a function, all subsequent code from that function will be stopped. But the defer code in F is executed. And then you get panic everywhere else you call F, and you pass it all the way up to the top of the stack, and then you crash.

Panic can be displayed as a result of a call to the panic function, as well as by some runtime error, such as an array out of bounds.

There are many articles on the Internet that say panic will only call the defer code of the current Goroutine, but this is incorrect, as in the following code:

func main(a) {
	go func(a) {
		defer fmt.Println("goroutine1 invoke")
		go func(a) {
			defer fmt.Println("goroutine2 invoke")
			go func(a) {
				defer fmt.Println("goroutine3 invoke")
				panic("panic")
			}()
		}()
	}()

	time.Sleep(1 * time.Second)
} 
Copy the code

There is a high probability that the following will be output:

goroutine1 invoke
goroutine2 invoke
goroutine3 invoke
panic: panic
Copy the code

To be exact, panic only guarantees that the defer code in the current Goroutine will be executed; the defer code in other goroutines is not guaranteed to be executed.

3. recover

Recover is also a built-in function of Go that can recover the normal execution of a program from a panic. Recover needs to be defined together with defer.

In a normal process, the execution of RECOVER would have no impact. Only in the event of a panic does Recevoer restore the application and prevent it from crashing. Only the defer code will be executed when a panic occurs. So recover only makes sense when paired with defer.

Recover and panic must be used in the same Goroutine. Applications cannot be recovered across goroutine.

go func() {
		defer fmt.Println("goroutine1 invoke")
		go func() {
			defer fmt.Println("goroutine2 invoke")
			go func() {

				defer func() {
					recover()
				}()
				defer fmt.Println("goroutine3 invoke")
				panic("panic")

			}()
		}()
	}()

time.Sleep(1 * time.Second)
Copy the code

The following program does not crash, but if the call to recover is not in the same Goroutine, you cannot prevent it from crashing.

go func() {
		defer fmt.Println("goroutine1 invoke")
		go func() {

			defer func() {
				recover()
			}()
			defer fmt.Println("goroutine2 invoke")

			go func() {
				defer fmt.Println("goroutine3 invoke")
				panic("panic")
			}()
			
		}()
	}()

	time.Sleep(1 * time.Second)
Copy the code

4. Summary

Defer, panic, and recover are flow control modes provided by Go. Defer can be used for normal code flow and operations such as closing resources. Panic can be used to indicate that a program has a big problem and needs to be terminated, which can be triggered by itself or by runtime errors. But in cases where we don’t want the program to terminate due to a panic, such as web services, we can recover the program using Recoever.

This paper is based on GO1.14

The text/Rayjun

[1] blog.golang.org/defer-panic…