This is a creation in Article, where the information may have evolved or changed.
I. Overview of DEFER
defer
is 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
panic
Will 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.