go function calls defer lazily

content

1. Execution order of defer

2. Delayed execution order

1. Use delayed concurrent unlocking

2. Use delayed release of file handles


        When the function to which defer belongs is about to return, the deferred-processed statements are executed in the reverse order of defer, that is, the first defer statement is executed last, and the last defer statement is executed first. Statements that are not defer are still executed in the order in which they were executed.

1. Execution order of defer

package main
import (
    "fmt"
)
func main() {
    fmt.Println("defer begin")
    // 将defer放入延迟调用栈
    defer fmt.Println(1)
    defer fmt.Println(2)
    // 最后一个放入, 位于栈顶, 最先调用
    defer fmt.Println(3)
    fmt.Println("defer end")
}

代码输出如下:
defer begin
defer end
3
2
1

2. Delayed execution order

The defer statement is exactly the statement executed when the function exits, so the use of defer can be very convenient to deal with the problem of resource release.

1. Use delayed concurrent unlocking

In the following example, map will be used concurrently in the function. To prevent race conditions, sync.Mutex is used to lock, see the following code:

var (
    // 一个演示用的映射
    valueByKey      = make(map[string]int)
    // 保证使用映射时的并发安全的互斥锁
    valueByKeyGuard sync.Mutex
)

// 根据键读取值
func readValue(key string) int {
    // 对共享资源加锁
    valueByKeyGuard.Lock()
    // 取值
    v := valueByKey[key]
    // 对共享资源解锁
    valueByKeyGuard.Unlock()
    // 返回值
    return v
}

Use the defer statement to simplify the above statement, refer to the following code.

func readValue(key string) int {
    valueByKeyGuard.Lock()
   
    // defer后面的语句不会马上调用, 而是延迟到函数结束时调用
    defer valueByKeyGuard.Unlock()
    return valueByKey[key]
}

2. Use delayed release of file handles

The operation of a file needs to go through several processes of opening the file, acquiring and operating the file resource, and closing the resource. If the file resource is not closed after the operation, the process will never be able to release the file resource.

// 根据文件名查询其大小
func fileSize(filename string) int64 {
    // 根据文件名打开文件, 返回文件句柄和错误
    f, err := os.Open(filename)
    // 如果打开时发生错误, 返回文件大小为0
    if err != nil {
        f.close()
        return 0
    }
    // 取文件状态信息
    info, err := f.Stat()
   
    // 如果获取信息时发生错误, 关闭文件并返回文件大小为0
    if err != nil {
        f.Close()
        return 0
    }
    // 取文件大小
    size := info.Size()
    // 关闭文件
    f.Close()
   
    // 返回文件大小
    return size
}

In the above example, the bolded part is the close operation of the file. The following uses defer to simplify the code, the code is as follows:

func fileSize(filename string) int64 {
    f, err := os.Open(filename)
    if err != nil {
        return 0
    }
    
    // 延迟调用Close, 此时Close不会被调用
    defer f.Close()
    info, err := f.Stat()
    if err != nil {
        // defer机制触发, 调用Close关闭文件
        return 0
    }
    size := info.Size()
    // defer机制触发, 调用Close关闭文件
    return size
}

Guess you like

Origin blog.csdn.net/demored/article/details/124197261