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)
}
}

go-defer语句的更多相关文章

  1. [Go] defer 语句

    Go 还有一些特有的流程控制语句,其中一个就是 defer 语句.该语句用于延迟调用指定的函数,它只能出现在函数的内部,由 defer 关键字以及针对某个函数的调用表达式组成.这里被调用的函数称为 延 ...

  2. go语言之goto语句和函数和defer语句

    1.goto关键字 import "fmt" func main() { for i := 0;i <11;i++{ if i == 2{ //关键字,goto跳转到某个位置 ...

  3. golang学习 ---defer语句

    golang语言defer特性详解 defer语句是go语言提供的一种用于注册延迟调用的机制,它可以让函数在当前函数执行完毕后执行,是go语言中一种很有用的特性.由于它使用起来简单又方便,所以深得go ...

  4. go语言的defer语句

    转: https://www.jianshu.com/p/5b0b36f398a2 ---------------------------------------------------------- ...

  5. Go语言中defer语句使用小结

    defer是Go语言中的延迟执行语句,用来添加函数结束时执行的代码,常用于释放某些已分配的资源.关闭数据库连接.断开socket连接.解锁一个加锁的资源.Go语言机制担保一定会执行defer语句中的代 ...

  6. 探究 Go 语言 defer 语句的三种机制

    Golang 的 1.13 版本 与 1.14 版本对 defer 进行了两次优化,使得 defer 的性能开销在大部分场景下都得到大幅降低,其中到底经历了什么原理? 这是因为这两个版本对 defer ...

  7. Go语言学习——函数二 defer语句

    函数 package main import "fmt" // 函数:一段代码的封装 func f1(){ fmt.Println("Hello 中国!") } ...

  8. go defer 语句会延迟函数的执行直到上层函数返回。

    defer code... 可以理解为 执行完当前defer所在的方法代码后执行defer 中的代码 常用在释放资源 比如 关闭文件 为防止忘记编写关闭代码 可以先写好   defer  各种释放资源 ...

  9. 【Go入门教程3】流程(if、goto、for、switch)和函数(多个返回值、变参、传值与传指针、defer、函数作为值/类型、Panic和Recover、main函数和init函数、import)

    这小节我们要介绍Go里面的流程控制以及函数操作. 流程控制 流程控制在编程语言中是最伟大的发明了,因为有了它,你可以通过很简单的流程描述来表达很复杂的逻辑.Go中流程控制分三大类:条件判断,循环控制和 ...

  10. go:defer

    defer:延迟. 假设有调用函数A.被调用函数B,其关系如下: func A(){//调用函数 ... defer B()//被调用函数 ... return//B将延迟到return前执行 } * ...

随机推荐

  1. charles DNS欺骗

    本文参考:charles DNS欺骗 DNS欺骗/DNS Spoofing 功能:通过将您自己的主机名指定给远程地址映射来欺骗DNS查找 一般的开发流程中,在上线之前都需要在测试环境中先行进行验证,而 ...

  2. Qt信号槽-原理分析

    目录 一.问题 二.Moc 1.变量 2.Q_OBJECT展开后的函数声明 3.自定义信号 三.connect 四.信号触发 1.直连 2.队列连接 五.总结 六.推荐阅读 一.问题 学习Qt有一段时 ...

  3. 从Hybrid到React-Native: JS在移动端的南征北战史

    注:因为不了解Dart,所以本文不对flutter相关内容进行阐述, 实在抱歉 Hybrid Hybird是一种混合开发应用,可以实现JS和Java代码的互通,单纯使用ios/android原生实现, ...

  4. hibernate集成ehcahe进行缓存管理

    ehcace是现在非常流行的缓存框架,有轻量.灵活.可扩展.支持集群/分布式等优点. 在项目中,使用ehcace可以对数据进行缓存(一般使用.基于注解.基于aop),使用filter可以对页面进行缓存 ...

  5. JavaScript之深入函数(一)

    在任何编程语言中,函数的功能都是十分强大的,JavaScript也不例外.之前已经讲解了函数的一些基本知识,诸如函数定义,函数执行和函数返回值等,今天就带大家深入了解JavaScript中函数的原理及 ...

  6. 接口测试时如何选择Encoding(针对请求数据内包含中文)

    如果请求数据中包含中文,需要将Encoding选择为utf-8

  7. Android Studio [ImageView/使用第三方库加载图片]

    ImageViewActivity.class package com.xdw.a122; import android.support.v7.app.AppCompatActivity; impor ...

  8. [技术栈]C#利用Luhn算法(模10算法)对IMEI校验

    1.Luhn算法(模10算法) 通过查看ISO/IEC 7812-1:2017文件可以看到对于luhn算法的解释,如下图: 算法主要分为三步: 第一步:从右边第一位(最低位)开始隔位乘2: 第二步:把 ...

  9. 自定义TabLayout的Indicator

    最近项目要使用类似TabLayout的控件,其实我感觉就是TabLayout只是换了一个Indicator,先说一说TabLayout这是Android Support Design的控件要使用的同学 ...

  10. JS 生成唯一值UUID

    md5加密new Date()生成的值可能不是唯一的,另一种生成唯一值的方式: getUID: function() { // 获取唯一值 return 'xxxxxxxx-xxxx-4xxx-yxx ...