Go语言defer分析

什么是defer?

defer语句是专门在函数结束之后作一些清理工做的。咱们先举一个例子来更好的理解,如今有一个函数,它的做用是把一个文件内容拷贝到另外一个文件。golang

func CopyFile(dstName string, 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)
	src.Close()
	dst.Close()
	return
}

以上代码是能够正常执行的,可是存在一个问题,若是os.Create执行失败,那么就没法执行到文件资源的Close函数。进程每打开一个文件就会占用一个文件描述符,而在系统当中,文件描述符是有上限的,能够经过ulimit -n查看,若是资源没有被及时释放,会出现资源浪费的状况。若是打开文件过多,也会出现Too many open files的提示。这个时候就须要经过defer来解决问题了,代码以下。c#

func CopyFile(dstName string, 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()

	written, err = io.Copy(dst, src)
	return
}

defer语句会在return参数设置以后、函数返回给调用者以前执行,这样就再也不担忧文件资源没法被Close了。数据结构

defer的三个规则

规则一:被deferred的函数参数在defer时肯定

func a() {
	i := 0
	defer fmt.Println(i)
	i++
	return
}

咱们经过以上代码来理解这个拗口的规则,若是根据官方的定义来理解这段代码,变量i的值铁定为1,但实际执行的结果不是1,倒是0。函数

Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function is not invoked. Instead, deferred functions are invoked immediately before the surrounding function returns, in the reverse order they were deferred.lua

那咱们再从新来理解这个规则,变量i是在逐行执行到defer语句的时候就已经肯定了值,这个时候变量i尚未进行自增,因此输出的结果应该是0而不是1。code

规则二:被deferred函数执行顺序遵循LIFO原则

func b() {
    for i := 0; i < 4; i++ {
        defer fmt.Print(i)
    }
}

LIFO全称为Last In First Out,意为后进先出,栈是一种典型的LIFO数据结构。defer也是如此,拿以上代码为例,前后遍历了四次,也就是作了四次压栈操做。同理,在函数return以前,就会逐一出栈,倒序执行defer语句,因此上述代码输出内容为3210blog

规则三:deferred函数能够读取和修改函数的返回值

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

咱们定义一个defer函数,将变量i自增,那么最终变量i的值为2。咱们从官方文档中能够看出,defer语句是在函数设置返回值后,且在返回给主调函数前执行的,根据这个思路,c函数已经return了1,这个时候执行了defer函数,将返回的结果1进行了自增,而后返回给主调函数,这个时候主调函数拿到的值就是2了。进程

deferred functions are executed after any result parameters are set by that return statement but before the function returns to its caller资源

相关文章
相关标签/搜索