Go 语言中 defer 如何运行

Go 语言中 defer 如何运行

Posted by 锐玩道 on April 21, 2021

如果❤️我的文章有帮助,欢迎点赞、关注。这是对我继续技术创作最大的鼓励。更多往期文章在我的个人博客

defer 英语中有延迟押后,而”人如其名” —— Go语言的 defer 语句也会将其后面跟随的语句进行延迟处理。

具体是怎么个延迟法?我们先来看个例子:

函数return之后、结束前被执行

func returnAndDefer() int {
	defer func() {
		fmt.Println("defer func called")
	}()

	return func() int {
		fmt.Println("return func called")
		return 0
	}()
}

returnAndDefer函数的执行会使标准输出上打印出

return func called
defer func called

函数 returnAndDefer 的功能是打印出 defer func calledreturn func called 两条语句。 我们通过观察它们打印顺序得出 defer/return 被执行顺序。 func(){}() 为Go语言匿名函数写法,这里就不是主题就先不纠结。

请注意returnAndDefer函数中的倒数第二条语句defer func() {}。 当这条defer语句被执行的时候,其中的 defer func called 匿名方法并不会被立即执行。 它的确切的执行时机是在其所属的函数执行即将结束的那个时刻,也就是returnAndDefer函数return之后,函数结束之前。 也就是说,在returnAndDefer函数真正结束执行的前一刻,fmt.Println("defer func called")才会被执行。

这也是defer语句被如此命名的原因。语句 defer 在 函数即将结束时执行 的特性非常适合 读取完文件内容后一定要关闭查询完数据库后关系数据库链接 等场景 defer语句可以保证在函数将结果返回给调用方之前,那个之前占用的资源一定会被被销毁,是一种非常便捷和有效的保险措施。

学费的童鞋不妨做下下面的输出

func testReturnAndDefer()(t int){
	defer func(){
		t = t *10
	}()
	
	return 1
}

testReturnAndDefer()本应的返回值是1,但是在return之后,又被defer的匿名函数执行。 所以t=t*10被执行,最后testReturnAndDefer()返回结果为10

多个 defer, 后进先出

多个 defer 出现的时候,它就是一个后进先出堆栈 关系,举个例子:

func manyDefer() {
	defer func() {
		fmt.Print(1)
	}()

	defer func() {
		fmt.Print(2)
	}()

	defer func() {
		fmt.Print(3)
	}()
	
	

	defer func() {
		fmt.Print(4)
	}()
}

manyDefer函数的执行会使标准输出上打印出4321,哪怕是下方遍历打印之后的输出也是一样

func manyDeferV2() {
	for i := 1; i < 5; i++ {
		defer fmt.Print(i)
	}
}

练习题

所谓光说不练假把式,各有勇士把答案打在留言上

func manyDeferV3() {
	for i := 1; i < 5; i++ {
		defer func() {
			fmt.Print(i)
		}()
	}

	fmt.Println()
	for i := 1; i < 5; i++ {
		defer func(n int) {
			fmt.Print(n)
		}(i)
	}

}

完整代码

package main

import (
	"fmt"
)

func main() {
	returnAndDefer()
	fmt.Println(testReturnAndDefer())

	manyDefer()

	manyDeferV2()

	fmt.Println()

	manyDeferV3()
}

func returnAndDefer() int {
	defer func() {
		fmt.Println("defer func called")
	}()

	return func() int {
		fmt.Println("return func called")
		return 0
	}()
}

func testReturnAndDefer()(t int){ //t初始化0,作用域为该函数全域
	defer func(){
		t = t *10
	}()

	return 1
}


func manyDefer() {
	defer func() {
		fmt.Print(1)
	}()

	defer func() {
		fmt.Print(2)
	}()

	defer func() {
		fmt.Print(3)
	}()

	defer func() {
		fmt.Print(4)
	}()
}

func manyDeferV2() {
	for i := 1; i < 5; i++ {
		defer fmt.Print(i)
	}
}


func manyDeferV3() {
	for i := 1; i < 5; i++ {
		defer func() {
			fmt.Print(i)
		}()
	}

	fmt.Println()
	for i := 1; i < 5; i++ {
		defer func(n int) {
			fmt.Print(n)
		}(i)
	}

}