首页 技术 正文
技术 2022年11月8日
0 收藏 555 点赞 1,189 浏览 1359 个字
Go语言中的defer语句也非常独特。
defer语句仅能被放置在函数或方法中。
它由关键字defer和一个调用表达式组成。
调用表达式所表示的既不能是对Go语言内建函数的调用
也不能是对Go语言标准库代码包unsafe中的那些函数的调用。
实际上,满足上述条件的调用表达式被称为表达式语句。
func readFile(path string) ([]byte, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
return ioutil.ReadAll(file)
}
打开指定文件且未发现有错误发生之后,紧跟了一条defer语句。
其中携带的表达式语句表示的是对被打开文件的关闭操作。
注意,当这条defer语句被执行的时候,其中的这条表达式语句并不会被立即执行。
它的确切的执行时机是在其所属的函数(这里是readFile)的执行即将结束的那个时刻。
在readFile函数真正结束执行的前一刻,file.Close()才会被执行。
这也是defer语句被如此命名的原因。
语句defer file.Close()的含义是在打开文件并读取其内容后及时地关闭它。
该语句可以保证在readFile函数将结果返回给调用方之前,那个文件或目录一定会被关闭。
这实际上是一种非常便捷和有效的保险措施。
当一个函数中存在多个defer语句时,它们携带的表达式语句的执行顺序一定是它们的出现顺序的倒序。
下面的示例可以很好的证明这一点:
func deferIt() {
defer func() {
fmt.Print()
}()
defer func() {
fmt.Print()
}()
defer func() {
fmt.Print()
}()
fmt.Print()
}
deferIt函数的执行会使标准输出上打印出4321
defer携带的表达式语句代表的是对某个函数或方法的调用。这个调用可能会有参数传入。
如果代表传入参数的是一个表达式,那么在defer语句被执行的时候该表达式就会被求值了。
func deferIt3() {
f := func(i int) int {
fmt.Printf("%d ",i)
return i *
}
for i := ; i < ; i++ {
defer fmt.Printf("%d ", f(i))
}
}
它在被执行之后,标准输出上打印出1 。
defer携带的表达式语句代表的是对匿名函数的调用,那么我们就一定要非常警惕。请看下面的示例:
func deferIt4() {
for i := ; i < ; i++ {
defer func() {
fmt.Print(i)
}()
}
}
deferIt4函数在被执行之后标出输出上会出现5555,而不是4321
原因是defer语句携带的表达式语句中的那个匿名函数包含了对外部(确切地说,是该defer语句之外)的变量的使用。
注意,等到这个匿名函数要被执行(且会被执行4次)的时候,包含该defer语句的那条for语句已经执行完毕了。
此时的变量i的值已经变为了5。因此该匿名函数中的打印函数只会打印出5。
正确的用法是:把要使用的外部变量作为参数传入到匿名函数中。
修正后如下:
func deferIt4() {
for i := ; i < ; i++ {
defer func(n int) {
fmt.Print(n)
}(i)
}
}
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,114
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,586
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,432
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,203
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,838
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,923