Golang Defer

Wenchao · · 910 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

Defer

Go的控制流有一些常用的机制:if, for, switch, goto. 它也拥有可以在独立的goroutine中运行代码的go语句。接下来会介绍通常比较少用到的类型:defer, panic, recover.

defer语句将函数调用压入一个列表。当包围defer的函数返回的时候,列表中缓存的调用开始执行。Defer语句是用来简化各种各样的清除操作的

例如,当需要打开两个文件,将其中一个文件的内容拷贝到另外一个文件的时候:

func CopyFile(dstName, srcName string) (written int64, err error) {
    src, err := os.Open(srcName)
    if err != nil {
        return
    }
    
    dst, err := os.Create(dstName)
    if err != nil {
        return
    }
    
    written, err = io.Copy(dst, src)
    dst.Close()
    src.Close()
    return
}

上面的代码可以工作,但是会有一个Bug。如果调用os.Create失败,这个函数就会立即返回却没有关闭源文件。当然,可以在出现error的地方加上src.Close方法,但是如果这个函数非常复杂,这个问题就会很难被注意到。当引入defer语句,这个问题就会很容易被解决:

func CopyFile(dstName, srcName string) (written int64, err error) {
    src, err := os.Open(srcName)
    if err != nil {
        return
    }
    defer src.Close()
    
    dst, err := os.Create(dstName)
    if err != nil {
        return
    }
    defer dst.Close()
    
    return io.Copy(dst, src)
}

Defer 语句可以确保我们打开文件之后会关闭这些文件,不管函数中有多少个return语句。

Defer 语句的行为非常直接,可以预测。有三个简单的规则:

  1. defer语句指定的函数中的变量是当执行到defer语句的时候就确定了的;
    在下面的例子中,表达式“i”的值当Println被defer的时候就确定了的,所以下面的输出是0,而不是1

    func a() {
        i := 0
        defer fmt.Println(i)
        i++
        return
    }
    
  2. 多个defer 语句执行的顺序是后进先出的。
    下面的函数打印“3210”

    func b() {
        for i := 0; i < 4; i++ {
            defer fmt.Print(i)
        }
    }
    
  3. 被Defer的函数可以读取并且修改外层函数的被命名的返回值
    在下面的例子中,当外层函数返回的时候,defer函数执行,并且将返回值加1,所以这个函数返回的是2.

    func c() (i int) {
        defer func() {i++} ()
        return 1
    }
    

有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:Wenchao

查看原文:Golang Defer

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

910 次点击  
加入收藏 微博
上一篇:ngModel
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传