Defer the keyword

Many modern programming languages have the defer keyword. Go’s defer executes the function passed in before the current function returns. It is often used to close file descriptors, close database connections, and unlock resources.

The most common scenario for using defer is to do some finishing work after a function call, such as rolling back a database transaction in defer:

Func InsertObj() error {// get a database session db := db.getdb ().begin () defer d.rollback () //do someting err := db.insert () if err ! = nil{ return err } return db.Commit().Error }Copy the code

When using a database transaction, we can use the code above to call Rollback immediately after the transaction is created to ensure that the transaction will be rolled back. Even if the transaction did execute successfully, calling Commit() followed by Rollback() would not affect the committed transaction.

The characteristics of the defer

  • deferAnd how many timesdeferTime order of execution
  • deferWhen parameters are passed by value, the calculation is performed, which results in an unexpected result
func main() {

	defer fmt.Println(0)
        defer fmt.Println(1)
        defer fmt.Println(2)
        defer fmt.Println(3)
        	
}

Copy the code

Output from the code above:

3
2
1
0
Copy the code

The order in which defer is executed is first in, then last out

func main() {
    {
        defer fmt.Println("defer runs")
        fmt.Println("block ends")
    }
    
    fmt.Println("main ends")
}
Copy the code

Output:

block ends
main ends
defer runs
Copy the code

You can see that defer is not executed when it exits the scope of the code block; it will only be called before the current function and method return

Is a

func main() {
	startedAt := time.Now()
	defer fmt.Println(time.Since(startedAt))
	
	time.Sleep(time.Second)
}
Copy the code

Output:

0s
Copy the code

Calling the defer keyword immediately copies the external parameters referenced in the function, so the result of time.since (startedAt) is computed not before main exits, but when the defer keyword is invoked, resulting in the above code output of 0s.

So if you want to solve this problem you can rewrite the code

func main() {
	startedAt := time.Now()
	defer func() { fmt.Println(time.Since(startedAt)) }()
	
	time.Sleep(time.Second)
}

Copy the code

Output:

1s
Copy the code

Value passing is also used when the defer keyword is called, but it is because the function pointer is copied

The common case of defer

Catch exception and crash logs:

Func process() error {defer func() {if err := recover(); err ! = nil {// Crash log capture core.lognc.Errorf("panic: %v", err) core.LogPnc.Errorf("%s", string(debug.Stack())) } }() //do something err := obj.CALL(parseYML) if err ! = nil { return err } return nil }Copy the code

Release the lock:

Func runTask() {// lock c.lk.lock () // release the lock defer C.lk.lock () //do something}Copy the code

The business operation is performed before the function returns

Func (c *ProcessEngine) Process(ph * proceshook) {defer func() {defer func() {defer func() {defer func() {defer func() {defer func() {defer func() {defer func() {defer func() {defer func() {defer func() something }Copy the code

If you have any questions or want to know more, you can follow my official accountJim the Superhero, left a message on the official account, I saw the first reply.