This is a creation in Article, where the information may have evolved or changed.
I. Overview of DEFER
deferis a golang unique process Control statement that delays the run time of a specified statement, runs only inside the function, and is called when the function that he belongs to is run out. For example:
1 2 3 4
|
funcdefertest() { defer FMT. Println ("Hellodefer") Fmt. Println ("HelloWorld") }
|
It will print out first and HelloWorld then print out HelloDefer .
If there are multiple in a function defer , the order of operation and the order of the calls in the function are reversed, because they are all written in the stack:
1 2 3 4 5
|
Func defertest () { Defer FMT. Println ("HelloDefer1") Defer FMT. Println ("HelloDefer2") Fmt. Println ("HelloWorld") }
|
Operation Result:
1 2 3
|
Fmt. Println ("HelloDefer2") Fmt. Println ("HelloDefer1") Fmt. Println ("HelloWorld")
|
Second, defer and return
In a return function that contains statements, defer the run order is return after, but the defer code fragment that is running takes effect:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
func main(){ FMT. Println (Deferreturn) } func deferreturn() int{ I: = 1 defer func(){ FMT. Println ("Defer") i + = 1 }() return func()int{ FMT. Println ("Return") return i }() }
|
Operation Result:
It's obvious that it's going to defer return run after that! But one problem is that defer in executing the statement i +=1 , the value returned by this logic i should be 2 instead 1 . This problem is return caused by the operating mechanism: return when an object is returned, if the return type is not a pointer or a reference type, then the return object returned will not be a copy of the objects themselves.
We can verify this view:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
func main(){ ... FMT. PRINTLN ("main:", X, &x) } func deferreturn() int{ ... defer ... { FMT. Println ("Defer:", I, &i) ... }() return ... { FMT. Println ("Return:", I, &i) ... }() }
|
The output of the program is:
1 2 3
|
Return: 10xc042008238 Defer: 10xc042008238 Main: 1 0xc042008230 the address of I in the //main function is not the same as the address of I in Deferreturn ()
|
If you change the return value of a function to a pointer type, the return value in the main function is consistent with the body of the function:
1 2 3 4 5 6 7 8 9 10 11 12 13 Span class= ' line ' >14 15 16 |
Func Main () { x: = Deferreturn () Fmt. Println ("Main: ", X, *x) } Func Deferreturn () *int{ I: = 1 P: = &i Defer func () { *p + = 1 Fmt. Println ("Defer: ", p, *p) }() return func () *int{ Fmt. Println ("Return: ", p, *p) Return P }() }
|
Results:
1 2 3
|
Return: 0xc0420361d1 defer: 0xc0420361d2 Main: 0xc0420361d2
|
Iii. Defer and panic
panicWill defer spread the panic to other functions after it has run out:
1 2 3 4
|
Func Deferpanic () { Defer FMT. Println ("Hellodefer") Panic ("Hey, I" M Panic ") }
|
Results:
1 2 3 4 5 6 7
|
Hellodefer //will output the code of the defer section first Panic:hey, I "M panic Goroutine 1 [Running]: Main.defertest () E:/code/golang/src/test_src/defer/main.go:12 +0XFC Main.main () E:/code/golang/src/test_src/defer/main.go:6 +0x27
|
Iv. defer and for loops
Do not defer use external variables inside, which can cause some unexpected errors:
1 2 3 4 5 6 7
|
Func defertest () { For I: = 0; I < 5; I ++{ Defer func () { Fmt. Printf ("%d", i) }() } }
|
The result of its output is 55555 that the principle is simple, because defer will be called after the for loop finishes running, and the For loop I will have a value of 5, so the I value printed is 55555 .
However, if the delay function within the loop is passed in, the parameter is evaluated at the time the current defer statement executes:
1 2 3 4 5 6 7 |
funcdefertest() { for 0 5; I ++{ defer funcint) { Fmt. Printf ("%d", i) } (i) } }
|
This will print out 43210 instead 55555 of.