Golang中的延迟代码


GO语言中,defer代码块会在函数调用链表中增加一个函数调用,这个函数调用是发生在return 之后的,通常用来释放函数的内部变量。

假设有一个函数,打开文件并对文件进行若干读写,在这种函数中,经常会有提前返回的情况。如果这样的话,就需要关闭正在工作的文件描述符。可能你会写如下的代码:

// 不用defer
func ReadWrite() bool {
    file.Open("file")
    // 做一些工作
    if failureX {
        file.Close() 
        return false
    }
    if failureY {
        file.Close() 
        return false
    }
    file.Close() 
    return true
    }

在这个函数中出现了很多的重复代码,而defer语句是可以解决这些问题的,在defer后指定的函数会在函数退出前进行调用。

我们可以通过defer语句,将Close对应的内容放置在Open后面,可以使函数更加可读和健壮。

func ReadWrite() bool {
    file.Open("file")
    defer file.Close()  // file.Close() 被添加到了 defer 列表
    // 做一些工作
    if failureX {
        return false  // Close() 现在自动调用
    }
    if failureY {
        return false  // 这里也是
    }
    return true  // And here
}

我们再来看一个延迟函数的例子:

for i := 0 ; i < 5 ; i++ {
    defer fmt.Printf("%d ", i)
}

延迟的函数是按照后进先出(LIFO)的顺序执行的,所以上面for循环的例子会打印:4 3 2 1 0.利用defer也可以修改返回值,假设正在使用命名结果参数和函数符号,例如下面这个函数:

defer func() {
        /* ... */
}()     // ← () 在这里是必须的

或者这个例子,我们更容易理解为什么,以及在哪需要用括号。

defer func(x int) {
        /* ... */
}(5)    // 为输入参数 x 赋值 5

在这个defer匿名函数中,可以访问任何命名返回参数:

func f() (ret int) { ← ret 初始化为零
    defer func() {
        ret++  // ret 增加为 1
    }()
    return 0  // 返回的是 1 而不是 0! 
}

文章作者: RickDamon
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 RickDamon !
  目录