• go-defer语句


    Go语言中的defer语句也非常独特。
    defer语句仅能被放置在函数或方法中。
    它由关键字defer和一个调用表达式组成。
    调用表达式所表示的既不能是对Go语言内建函数的调用
    也不能是对Go语言标准库代码包unsafe中的那些函数的调用。
    实际上,满足上述条件的调用表达式被称为表达式语句。
    func readFile(path string) ([]byte, error) {
        file, err := os.Open(path)
        if err != nil {
            return nil, err
        }
        defer file.Close()
        return ioutil.ReadAll(file)
    }
    打开指定文件且未发现有错误发生之后,紧跟了一条defer语句。 其中携带的表达式语句表示的是对被打开文件的关闭操作。 注意,当这条defer语句被执行的时候,其中的这条表达式语句并不会被立即执行。 它的确切的执行时机是在其所属的函数(这里是readFile)的执行即将结束的那个时刻。 在readFile函数真正结束执行的前一刻,file.Close()才会被执行。 这也是defer语句被如此命名的原因。
    语句defer file.Close()的含义是在打开文件并读取其内容后及时地关闭它。
    该语句可以保证在readFile函数将结果返回给调用方之前,那个文件或目录一定会被关闭。
    这实际上是一种非常便捷和有效的保险措施。
    当一个函数中存在多个defer语句时,它们携带的表达式语句的执行顺序一定是它们的出现顺序的倒序。
    下面的示例可以很好的证明这一点:
    func deferIt() {
        defer func() {
            fmt.Print(1)
        }()
        defer func() {
            fmt.Print(2)
        }()
        defer func() {
            fmt.Print(3)
        }()
        fmt.Print(4)
    }
    deferIt函数的执行会使标准输出上打印出4321
    defer携带的表达式语句代表的是对某个函数或方法的调用。这个调用可能会有参数传入。
    如果代表传入参数的是一个表达式,那么在defer语句被执行的时候该表达式就会被求值了。
    func deferIt3() {
        f := func(i int) int {
            fmt.Printf("%d ",i)
            return i * 10
        }
        for i := 1; i < 5; i++ {
            defer fmt.Printf("%d ", f(i))
        }
    }
    它在被执行之后,标准输出上打印出1 2 3 4 40 30 20 10
    defer携带的表达式语句代表的是对匿名函数的调用,那么我们就一定要非常警惕。请看下面的示例:
    func deferIt4() {
        for i := 1; i < 5; i++ {
            defer func() {
                fmt.Print(i)
            }()
        }
    }     
    deferIt4函数在被执行之后标出输出上会出现5555,而不是4321
    原因是defer语句携带的表达式语句中的那个匿名函数包含了对外部(确切地说,是该defer语句之外)的变量的使用。
    注意,等到这个匿名函数要被执行(且会被执行4次)的时候,包含该defer语句的那条for语句已经执行完毕了。
    此时的变量i的值已经变为了5。因此该匿名函数中的打印函数只会打印出5。
    正确的用法是:把要使用的外部变量作为参数传入到匿名函数中。
    修正后如下:
    func deferIt4() {
        for i := 1; i < 5; i++ {
            defer func(n int) {
                fmt.Print(n)
            }(i)
        }
    }
  • 相关阅读:
    HDFS原理分析之HA机制:avatarnode原理
    [转]Hessian——轻量级远程调用方案
    [转]成为Java顶尖程序员 ,看这11本书就够了
    [转]Java四种线程池的使用
    [转]Java多线程
    IntelliJ IDEA 快捷键
    [转]django 日志logging的配置以及处理
    [转]使用TortoiseGit处理代码冲突
    动软DbHelperSQL
    [转]Entity Framework 的实体关系
  • 原文地址:https://www.cnblogs.com/osbreak/p/10402091.html
Copyright © 2020-2023  润新知