Defer keyword
The defer keyword allowsFunctions or statementsIt is delayed until the end of the function block, that is, when the function is about to exit, even if the function returns an error in the middle, even if it has already been panic (), even if the function has been returned, the defer object is also executed.
For example:
Func main () {A ()} func A () {println ("in a") Defer B () println ("leaving ") // B ()} func B () {println ("in B") println ("leaving B ")}
The output is as follows:
in aleaving ain bleaving b
Even if an error has been reported for a function or the function has been returned, the defer object will be executed at the last moment before the function exits.
Func A () type {... code... defer B ()... code... // return ARGs error returned by the function execution // function B () will be executed here}
However, note that the go scope uses the lexical scope. The location defined by defer determines the variable value that the object can see, rather than the value that can be seen when the object is called.
For example:
Package mainvar x = 10 func main () {A ()} func A () {println ("Start A:", X) // output 10 x = 20 defer B (X) x = 30 println ("leaving a:", x) // output 30 // call defer delayed object B (), output 20} func B (x int) {println ("start B:", x )}
Compare the following defer:
Package mainvar x = 10 func main () {A ()} func A () int {println ("Start A:", X) // output 10 x = 20 defer func () {println ("in defer:", x) // output 30} () x = 30 println ("leaving :", x) // output 30 return x}
The output value of the anonymous function that defer is 30. Shouldn't it be 20? First, change it to the following:
Package mainvar x = 10 func main () {A ()} func A () int {println ("Start A:", X) // output 10 x = 20 defer func (x INT) {println ("in defer:", x) // output 20} (X) X = 30 println ("leaving a:", x) // output 30 return x}
The deferred object sees 20, which is the same as the first one.defer b(x)
Is the same.
The reason is that if defer delays a function, it evaluates parameters and variables directly at its defined position. The copy and pass value of the copied value.. Therefore, in the cases of (1) and (3), at the position defined by defer, x = 20 is copied to the deferred function parameter, therefore, the operation inside the function is always a copy of X. In the second case, it points directly to the variable X = 20 that it sees. Then, the variable is a global variable. When x = 30 is executed, the value is modified, when the defer object is executed, the value of X to which it points has been modified.
Let's look at the example below, put defer into a statement block, and declare a new variable named X in this statement block:
Func A () int {println ("Start A:", x) // output 10 x = 20 {X: = 40 defer func () {println ("in defer: ", x) // output 40} ()} X = 30 println (" leaving a: ", x) // output 30 return x}
The above defer is defined in the statement block, and X can be seen in the statement block.x=40
Its X points to X in the statement block. On the other hand, when the statement block ends,x=40
But since the defer function still has x pointing to the value 40, the value 40 is still referenced by the defer function, it will not be recycled by GC until the defer execution is complete. Therefore, when the defer function is executed, the output is still 40.
If the statement block contains multiple defer, The defer object is executed in LIFO (last in first out) mode, that is, the defer object is defined first and then executed.
func main() { println("start...") defer println("1") defer println("2") defer println("3") defer println("4") println("end...")}
Output:
start...end...4321
What is the use of defer? It is generally used for aftercare operations, such as cleaning up garbage and releasing resources, and performing defer object regardless of whether an error is reported. On the other hand, defer can put the statement of these aftercare operations together with the start statement, improving both readability and security. After all, you can directly write the defer statement after writing the start statement, you will never forget to close the service or perform other operations.
For example, open a file and close the file together:
Open () Defer file. Close ()... Operation file...
The following are some common scenarios of defer:
- Open Close file
- Lock and release lock
- Establish and release connections
- Output end information as the end
- Clear garbage (such as temporary files)
Panic () and recover ()
Panic () is used to generate error messages and terminateCurrent goroutineGenerally, it is regarded as a function to exit the function where panic () is located and to exit the function that calls the function where panic () is located. For example, if you call panic () in F () and F (), F () Exits and g () exits.
Note: The deferred object of the defer keyword is the final call of the function. Even if a panic appears, the deferred object of defer is called.
For example, in the following code, main () Outputsstart main
Call a () and it will outputstart a
Then, panic () will outputpanic: panic in a
Then, an error is reported to terminate the program.
func main() { println("start main") a() println("end main")}func a() { println("start a") panic("panic in a") println("end a")}
The execution result is as follows:
start mainstart apanic: panic in agoroutine 1 [running]:main.a() E:/learning/err.go:14 +0x63main.main() E:/learning/err.go:8 +0x4cexit status 2
Note thatend a
Andend main
Are not output.
You can use recover () to capture panic () and resume execution. Recover () is used to capture panic () errors and return this error message. However, even if the recover () captures panic (), the function that calls the function that contains the panic () function (that is, the above g () function) will exit, so if the recover () function () if it is defined in G (), the code after calling the F () function in G () will not be executed (see the general format below ).
The following are common formats of panic () and recover:
Func main () {G () // the following code will execute... code in Main ...} func g () {defer func () {If STR: = recover (); Str! = Nil {FMT. println (STR )}}()... code in G ()... // F () must be called after the defer keyword F () // the following code in the function will not be executed... code in G ()...} func F (){... code1... panic ("error found") // the following code will not be executed... code in F ()...}
You can use recover () to capture panic () and resume execution. However, the following code is incorrect:
Func main () {println ("START main") A () println ("end main")} func A () {println ("start ") panic ("panic in a") // The incorrect panic_str: = recover () println (panic_str) println ("end ")}
The error occurs because the panic () exits the functions a () and main () as soon as it appears. In order for recover () to truly capture panic (), you need to put recover () in the deferred object of defer, and the definition of defer must be before the occurrence of panic.
For example, the following is an example of a common format:
package mainimport "fmt"func main() { println("start main") b() println("end main")}func a() { println("start a") panic("panic in a") println("end a")}func b() { println("start b") defer func() { if str := recover(); str != nil { fmt.Println(str) } }() a() println("end b")}
The output result is as follows:
start mainstart bstart apanic in aend main
Note thatend b
,end a
Are not output,end main
Output.
Panic () is a built-in function (in the package builtin), inlog
The package also has a panic () function, which calls print () to output information and then calls panic ().go doc log Panic
You can see at a glance:
$ go doc log Panicfunc Panic(v ...interface{}) Panic is equivalent to Print() followed by a call to panic().
Go basic series: Defer, panic, and recover