这篇文章主要介绍“Golang中关于defer的知识点有哪些”,在日常操作中,相信很多人在Golang中关于defer的知识点有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Golang中关于defer的知识点有哪些”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
总结一下defer这个内置关键字
1、defer是一种延迟处理机制,是在函数进行return之前进行执行。
2、defer是采用栈的方式执行,也就是说先定义的defer后执行,后定义的defer最先被执行。
正因为defer具备这种机制,可以用在函数返回之前,关闭一些资源。例如在某些操作中,连接了MySQL、Redis这样的服务,在函数返回之前,就可以使用defer语句对连接进行关闭。就类似oop语言中的
finally
操作一样,不管发生任何异常,最终都会被执行。其语法格式也非常的简单。
package main
import "fmt"
func main() {
function1()
}
func function1() {
fmt.Printf("1")
defer function2()
fmt.Printf("2")
}
func function2() {
fmt.Printf("3")
}
上述代码执行的结果是:
1
2
3
下面就来总结这六个小知识点:
1、defer 的执行顺序。 采用栈的方式执行,先定义后执行。
2、defer 与 return 谁先谁后。return 之后的语句先执行,defer 后的语句后执行。
3、函数的返回值初始化与 defer 间接影响。defer中修改了返回值,实际返回的值是按照defer修改后的值进行返回。
4、defer 遇见 panic。按照defer的栈顺序,输出panic触发之前定义好的defer。
5、defer 中包含 panic。按照defer的栈顺序,输出panic触发之前的defer。并且defer中会接收到panic信息。
6、defer 下的函数参数包含子函数。会先进行子函数的结果值,然后在按照栈的顺序进行输出。
defer的执行顺序是什么样的
关于这个问题,前面的示例代码也提到过了,采用栈的顺序执行。在定义时,压入栈中,执行是从栈中获取。
defer与return谁先谁后
先来看如下一段代码,最终的执行结果是怎么样的。
func main() {
fmt.Println(demo2())
}
func demo2() int {
defer func() {
fmt.Println("2")
}()
return func() int {
fmt.Println("1")
return 4
}()
}
运行上述代码,得到的结果是:
1
2
4
可能你会有一个疑问 ,既然都提到了defer是在函数返回之前执行,为什么还是先输出1,然后在输出2呢?关于defer的定义,就是在函数返回之前执行。这一点毋庸置疑,肯定是在return之前执行。需要注意的是,return 是非原子性的,需要两步,执行前首先要得到返回值 (为返回值赋值),return 将返回值返回调用处。defer 和 return 的执行顺序是先为返回值赋值,然后执行 defer,然后 return 到函数调用处。
函数的返回值初始化与defer间接影响
同样的方式,我们先看一段代码,猜测一下最终的执行结果是什么。
func main() {
fmt.Println(demo3())
}
func demo3() (a int) {
defer func() {
a = 3
}()
return 1
}
上诉代码,最终的运行结果如下:
3
跟上第2个知识点类似,函数在return之前,会进行返回值赋值,然后在执行defer语句,最终在返回结果值。
1、在定义函数demo3()时,为函数设置了一个int类型的变量a,此时int类型初始化值默认是0。
2、定义一个defer语句,在函数return之前执行,匿名函数中对返回变量a进行了一次赋值,设置 a=3。
3、此时执行return语句,因为return语句是执行两步操作,先为返回变量a执行一次赋值操作,将a设置为3。紧接着执行defer语句,此时defer又将a设置为3。
4、最终return进行返回,由于第3步的defer对a进行了重新赋值。因此a就变成了3。
5、最后main函数打印结果,打印的其实是defer修改之后的值。
如果将变量a的声明放回到函数内部声明呢,其运行的结果会根据return的值进行返回。
func main() {
fmt.Println(demo7())
}
func demo7() int {
var a int
defer func(a int) {
a = 10
}(a)
return 2
}
上述的最终结果返回值如下:
10
2
为什么会发生两种不同的结果呢?这是因为,这是因为发生了值拷贝现象。在执行defer语句时,将参数a传递给匿名函数时进行了一个值拷贝的过程。由于值拷贝是不会影响原值,因此匿名函数对变量a进行了修改,不会影响函数外部的值。当然传递一个指针的话,结果就不一样了。在函数定义时,声明的变量可以理解为一个全局变量,因此defer或者return对变量a进行了修改,都会影响到该变量上。
defer遇见panic。
panic是Go语言中的一种异常现象,它会中断程序的执行,并抛出具体的异常信息。既然会中断程序的执行,如果一段代码中发生了panic,最终还会调用defer语句吗?
func main() {
demo4()
}
func demo4() {
defer func() {
fmt.Println("1")
}()
defer func() {
fmt.Println("2")
}()
panic("panic")
defer func() {
fmt.Println("3")
}()
defer func() {
fmt.Println("4")
}()
}
运行上述代码,最终得到的结果如下: