defer使用语法

//defer后面必须是函数调用语句或方法调用语句,不能是其他语句,否则编译器会出错。
package main
import (
"fmt"
)
func foo(n int) int {
defer n++
//defer fmt.Println(n)
return n
}
func main() {
var i int = 100
foo(i)
}
# command-line-arguments
expression in defer must be function call
syntax error: unexpected ++ at end of statement

  

defer 语句的用途

含有 defer 语句的函数,会在该函数将要返回之前,调用另一个函数。

defer后面的函数在defer语句所在的函数执行结束的时候会被调用;

package main
import (
"fmt"
) type person struct {
firstName string
lastName string
} func (p person) fullName() {
fmt.Printf("%s %s",p.firstName,p.lastName)
} func main() {
p := person {
firstName: "John",
lastName: "Smith",
}
defer p.fullName()
fmt.Printf("Welcome ")
}

在上面的程序里的第 11 行,a 的初始值为 5。在第 12 行执行 defer 语句的时候,由于 a 等于 5,因此延迟函数 printA 的实参也等于 5。接着我们在第 13 行将 a 的值修改为 10。下一行会打印出 a 的值。该程序输出:

value of a before deferred function call 10  
value of a in deferred function 5

从上面的输出,我们可以看出,在调用了 defer 语句后,虽然我们将 a 修改为 10,但调用延迟函数 printA(a)后,仍然打印的是 5。

 

defer 栈

当一个函数内多次调用 defer 时,Go 会把 defer 调用放入到一个栈中,随后按照后进先出(Last In First Out, LIFO)的顺序执行。

我们下面编写一个小程序,使用 defer 栈,将一个字符串逆序打印。

package main
import (
"fmt"
) func main() {
name := "Naveen"
fmt.Printf("Orignal String: %s\n", string(name))
fmt.Printf("Reversed String: ")
for _, v := range []rune(name) {
defer fmt.Printf("%c", v)
}}
Orignal String: Naveen
Reversed String: neevaN

  

defer 的实际应用

  • file对象打开后的自动关闭
func CopyFile(dstName, srcName string) (written int64, err error) {
src, err := os.Open(srcName)
if err != nil {
return
}
defer src.Close() dst, err := os.Create(dstName)
if err != nil {
return
}
defer dst.Close() // other codes
return io.Copy(dst, src)
}

 在打开输入文件输出文件后,不管后面的代码流程如何影响,这两个文件能够被自动关闭。 

  • mutex对象锁住后的自动释放
func foo(...) {
mu.Lock()
defer mu.Unlock() // code logic
}

确保mu锁能够在函数foo退出之后自动释放。

  • WaitGroup的退出
package main
import (
"fmt"
"sync"
) type rect struct {
length int
width int
} func (r rect) area(wg *sync.WaitGroup) {
defer wg.Done()
if r.length < 0 {
fmt.Printf("rect %v's length should be greater than zero\n", r)
return
}
if r.width < 0 {
fmt.Printf("rect %v's width should be greater than zero\n", r)
return
}
area := r.length * r.width
fmt.Printf("rect %v's area %d\n", r, area)
} func main() {
var wg sync.WaitGroup
r1 := rect{-67, 89}
r2 := rect{5, -67}
r3 := rect{8, 9}
rects := []rect{r1, r2, r3}
for _, v := range rects {
wg.Add(1)
go v.area(&wg)
}
wg.Wait()
fmt.Println("All go routines finished executing")
}

  

 

最新文章

  1. [家里蹲大学数学杂志]第053期Legendre变换
  2. .NET中的流
  3. 四则运算GUI版本功能展现
  4. jquery 下了框
  5. 第三章——使用系统函数、存储过程和DBCC SQLPERF命令来监控SQLServer(3)
  6. CentOS 6.5静态IP的设置(NAT和桥接都适用)
  7. MyBatis3系列__04CRUD以及参数处理
  8. 【原创】单片系统SoC
  9. Vmware ESXi日志文件存放目录地址
  10. Vue 获得所选中目标的状态(checked)以及对应目标的数据,并进行相应的操作
  11. 微服务-封装-docker by daysn大雄
  12. pandas创建一个日期
  13. 通过atomic_flag简单自旋锁实现简单说明标准库中锁使用的memory_order
  14. PAT 1009 说反话 (20)(代码)
  15. linux编译内核make menuconfig报错Unable to find the ncurses libraries解决办法
  16. 【C语言】为什么指明数组的列数?
  17. HBase的compact分析
  18. mysql增删
  19. java递归排序
  20. 生成正射影像/DSM,等高线提取

热门文章

  1. apache中通过mod_rewrite实现伪静态页面的方法
  2. Grafana 6.4 正式发布!
  3. 由std::once_call 引发的单例模式的再次总结,基于C++11
  4. Android中三种常用解析XML的方式(DOM、SAX、PULL)简介及区别
  5. 刷新:重新发现.NET与未来
  6. 各种xml配置文件(所含内部标签及顺序)的提示功能是真的人性化
  7. MySQL 视图(合并多表数据)引发的严重性能问题
  8. surging 微服务引擎 -协议主机的Behavior特性
  9. 代码审计-MetInfo CMS任意文件读取漏洞
  10. 《锋利的jQuery》学习总结