defer
是Go的特有发明,常用来执行文件关闭等资源清理的工作。
defer
将 f.Close()
函数延迟到main
函数退出前才执行。
defer
会把要延迟运行的函数放到一个栈里(先进后出), 在defer
所在的函数运行结束后再从栈里一个个拿出来运行。
输出
多个defer
语句是放在栈
中,在main
函数退出前从栈中(先进后出)一个个取出运行。
defer
延迟的函数什么时候运行? 在**defer
所在的函数** 退出前运行。
输出
你能说说为什么会是这个结果吗?
defer 所在函数panic
后,仍然可以执行defer
延迟的函数。
输出
能输出3,2,1但打印不了main
了,因为panic
从foo
函数传到上层的main
函数,main
函数就立刻退出了。
panic是什么?
panic(恐慌)是一种意想不到的错误,或者是一种致命性的错误,程序必须终止。
- 例如除数为0的时候会panic:
输出panic
- 索引越界panic
输出panic:
- 自定义panic
输出panic:
panic()
生成一个自定义panic
, 可以传人任何类型的变量(说明引发panic的原因)。
把panic当做恐慌吧,不要把panic
作为错误处理,Go有自己的错误处理——error
接口。只有意想不到,或者致命性的错误才使用panic
。
在 defer 中使用recover
捕获panic
,使得程序继续运行(恢复)
输出
使用recover
后main
成功打印。
foo
函数的panic
被recover
捕获到了,没有继续传导到main函数,函数继续运行,打印main
注意, recover
必须在defer
语句中使用,因为defer
在程序panic时仍会运行。
recover()
返回的是any
类型,即引发panic
的原因, 也就是panic()
传进去的类型,在本例中是string: "噢噢 坏事发生了!"
。
- 在循环中使用panic:
输出
我们希望文件用完就关闭,而不是等待main函数退出是再关闭。使用一个匿名函数套住defer
输出
每次循环结束匿名函数退出前触发defer
语句。记住,defer
所在的函数退出前运行延迟函数。
- defer函数的参数在声明时就验证
函数该打印1, 还是2呢?
运行,输出
原因是defer
语句声明时就进行验证,此时a
=1
如果是下面代码,会发送什么?
输出
原因是只有参数进行验证。上述的defer后面函数是一个闭包,引用了外部变量a
, 在函数退出时, a = 2
所以打印2。
- defer 与命名返回值
考虑下列代码,会输出什么?
是输出1,2还是3呢?
运行,输出
为什么呢? return 2
相当于num = 2
, 之后defer
函数运行,num = 3
, 所以返回3。defer 可以改变函数 return
后的命名返回值。