defer of learning notes of Go programming language

defer of learning notes of Go programming language

I environment

  Centos8.5, go1.17.5 linux/amd64

 

II concept

Grammatically, a defer statement is an ordinary function or method call, and the keyword defer is added before the call.

 

Execution timing

No matter under normal circumstances, such as return or function execution, or under abnormal circumstances, such as downtime, the actual call is delayed until the end of the function containing the defer statement.

 

The defer statement does not limit the number of uses

Execute in the reverse order of the order in which the defer statement is called

 23 func main() {
 24     defer fmt.Println("a")
 25     defer fmt.Println("b")
 26     defer fmt.Println("c")
 27     fmt.Println("----------")
 28 }

The operation results are as follows

 

III Usage scenario

1. It is often used for paired operations, such as opening and closing, connecting and disconnecting, locking and unlocking. After successfully obtaining resources, use the defer statement.

   27 resp, err := http.Get(url)
   28 if err != nil {
   29     return err
   30 }
   31 defer resp.Body.Close()
   32-----------------------------
   33 f, err := os.Open(filename)
   34 if err != nil {
   35     return nil, err
   36 }
   37 defer f.Close()
   38 ----------------------------
   39 var mu sync.Mutex
   40 var m = make(map[string]int)
   41 func lookup(key string) int {
   42     mu.Lock()
   43     defer mu.Unlock()
   44     return m[key]
   45 }

  

2. Debug a complex function

1) The sample code in the book is as follows. At first, I didn't quite understand it. After reading it several times, I typed the code myself, read the book, and then reacted at once. The bigSlowOperation function has a complex operation. The code simulates the time-consuming operation in line 13. Set the debug behavior at the "entry" and "exit" of the bigSlowOperation function. The following is implemented by delaying the call to the trace function. Oh, no, this statement is wrong. It is implemented by delaying the call to the anonymous function returned by the trace function. Note that there is a parenthesis at the end of line 13, which indicates that it is a call to the anonymous function returned by the trace function, and the defer keyword modifies it.

When the bigSlowOperation function is executed, lines 17 and 18 of the code in the trace function are executed normally. From the results, you can see that the time when entering the bigSlowOperation function is printed. The call of anonymous function is delayed until the end of bigSlowOperation function. Through the results, you can see that after a pause of 3 seconds, the end time and exit are printed.

 10 func bigSlowOperation() {
 11     defer trace("bigSlowOperation")()
 12     fmt.Println("----------")
 13     time.Sleep(3 * time.Second)
 14 }
 15
 16 func trace(msg string) func() {
 17     start := time.Now()
 18     log.Printf("enter %s\n", msg)
 19     return func() { log.Printf("exit %s, (%s)\n", msg, time.Since(start)) }
 20
 21 }
 22
 23 func main() {
 24     bigSlowOperation()
 25 }

The operation results are as follows

2) verify again. Remove the defer keyword in line 11 of the above example code. You can think about the results first

During the execution of bigSlowOperation function, the anonymous function returned by trace function is called. In this process, first execute the content of trace function (print enter), and then execute the anonymous function returned (print exit).

The operation results are as follows

3) then, verify it again. On the basis of the above example code, add the defer keyword in line 11 and remove the last (), so you can think of the result by yourself.

At this time, the trace} function is called late, so it is not the anonymous function returned by the delayed call. The trace function is executed only after the bigSlowOperation function is completed, and only the word "enter" is printed. The anonymous function returned by the trace} function will never be executed because it is not called.

The operation results are as follows, in line with expectations.

 

IV other

Example

1) Initial situation

   28 func double(x int) int {
   29     return x + x
   30 }

2) Adjust

By naming the result variable and adding the defer statement, its parameters and results are output every time the function is called. That is, at the end of the double} function, the anonymous function is called and the parameters and results are printed.

 32 func double(x int) (result int) {
 33     defer func() { fmt.Printf("double(%d) = %d\n", x, result) }()
 34     return x + x
 35 }

Call the above function, and the print result is as follows

3) adjust again, add a function triple, and print its return result.

Delayed anonymous functions can change the result returned by the outer function to the caller. Before the result of the function triple , is returned, the anonymous function func() that delays the call modifies the value of the result , so the return value of the function triple , is 12 (8 + 4).

 23 func main() {
 24     //double(4)
 25     fmt.Println(triple(4))
 26 }
 27
 28 func double2(x int) int {
 29     return x + x
 30 }
 31
 32 func double(x int) (result int) {
 33     defer func() { fmt.Printf("double(%d) = %d\n", x, result) }()
 34     return x + x
 35 }
 36
 37 func triple(x int) (result int) {
 38     defer func() { result += x }()
 39     return double(x)
 40 }

The operation results are as follows

Added by lancia on Mon, 27 Dec 2021 06:31:53 +0200