首页 > 其他分享 >Go 语言系列20:defer 延迟调用

Go 语言系列20:defer 延迟调用

时间:2022-11-25 13:41:03浏览次数:36  
标签:defer 20 ... fmt Println func Go return

含有 ​​defer​​​ 语句的函数,会在该函数将要返回之前,调用另一个函数。简单点说就是 ​​defer​​ 语句后面跟着的函数会延迟到当前函数执行完后再执行。

下面是一个简单的例子:

package main

import "fmt"

func myPrint() {
fmt.Println("Go")
}

func main() {
defer myPrint()
fmt.Println("Let's")
}

首先,执行 ​​main​​​ 函数,因为 ​​myPrint()​​​ 函数前有 ​​defer​​​ 关键字,所以会在执行完 ​​main​​​ 函数后再执行 ​​myPrint()​​​ 函数,所以先打印出 ​​Let's​​​ ,再执行 ​​myPrint()​​​ 函数打印 ​​Go​​ 。运行该程序输出如下:

Let's
Go

上面的程序等价于下面的程序:

defer fmt.Println("Go")
fmt.Println("Let's")

Go 语言系列20:defer 延迟调用_参考文献

即时求值的变量快照

Go 语言系列20:defer 延迟调用_释放资源_02


使用 ​​defer​​ 只是延时调用函数,传递给函数里的变量,不应该受到后续程序的影响。

str := "Go"
defer fmt.Println(str)
str = "Let's"
fmt.Println(str)

同理,运行该程序会输出如下:

Let's
Go

Go 语言系列20:defer 延迟调用_参考文献

延迟方法

Go 语言系列20:defer 延迟调用_释放资源_02


​defer​​ 不仅能够延迟函数的执行,也能延迟方法的执行。

package main

import "fmt"

type Person struct {
firstName, lastName string
}

func (p Person) printName() {
fmt.Printf("%s %s", p.firstName, p.lastName)
}

func main() {
p := Person{"John", "Smith"}
defer p.printName()
fmt.Printf("Hello ")
}

运行该程序输出如下:

Hello John Smith

Go 语言系列20:defer 延迟调用_参考文献

defer 栈

Go 语言系列20:defer 延迟调用_释放资源_02


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

package main

import "fmt"

func main() {
defer fmt.Printf("Caizi.")
defer fmt.Printf("am ")
defer fmt.Printf("I ")
fmt.Printf("Hello! ")
}

运行上面的程序输出如下:

Hello! I am Caizi.

Go 语言系列20:defer 延迟调用_参考文献

defer 在 return 后调用

Go 语言系列20:defer 延迟调用_释放资源_02


看看下面的例子你就知道了:

package main

import "fmt"

var x int = 100

func myfunc() int {
defer func() {x = 200}()
fmt.Println("myfunc: x =", x)
return x
}

func main() {
myx := myfunc()
fmt.Println("main: x =", x)
fmt.Println("main: myx =", myx)
}

运行该程序输出如下:

myfunc: x = 100
main: x = 200
main: myx = 100

Go 语言系列20:defer 延迟调用_参考文献

defer 可以使代码更简洁

Go 语言系列20:defer 延迟调用_释放资源_02


如果没有使用 ​​defer​​​ ,当在一个操作资源的函数里调用多个 ​​return​​ 时,每次都得释放资源,你可能这样写代码:

func f() {
r := getResource() //0,获取资源
......
if ... {
r.release() //1,释放资源
return
}
......
if ... {
r.release() //2,释放资源
return
}
......
if ... {
r.release() //3,释放资源
return
}
......
r.release() //4,释放资源
return
}

有了 ​​defer​​ 之后,你可以简洁地写成下面这样:

func f() {
r := getResource() //0,获取资源

defer r.release() //1,释放资源
......
if ... {
...
return
}
......
if ... {
...
return
}
......
if ... {
...
return
}
......
return
}

参考文献:

[1] Alan A. A. Donovan; Brian W. Kernighan, Go 程序设计语言, Translated by 李道兵, 高博, 庞向才, 金鑫鑫 and 林齐斌, 机械工业出版社, 2017.




标签:defer,20,...,fmt,Println,func,Go,return
From: https://blog.51cto.com/u_15891283/5886551

相关文章

  • Go 语言系列23:接口
    在Go语言中,接口就是方法签名(MethodSignature)的集合。在面向对象的领域里,接口定义一个对象的行为,接口只指定了对象应该做什么,至于如何实现这个行为,则由对象本身去确定......
  • Go 语言系列22:方法
    方法其实在之前结构体那边简单讲过,方法其实就是一个函数,在​​func​​这个关键字和方法名中间加入了一个特殊的接收器类型。接收器可以是结构体类型或者是非结构体类型......
  • Go 语言系列24:go 协程
    Go协程是与其他函数或方法一起并发运行的函数或方法。Go协程可以看作是轻量级线程。与线程相比,创建一个Go协程的成本很小。因此在Go应用中,常常会看到有数以千计的Go......
  • Go 语言系列21:goto 无条件跳转
    在Go语言中保留​​goto​​​这点我确实没想到,毕竟很多人不建议使用​​goto​​​语句。​​goto​​后面接的是标签,表示下一步要执行哪里的代码。gotolabel...la......
  • LeetCode 20.有效的括号(简单)
    题目描述:给定一个只包括​​'('​​​,​​')'​​​,​​'{'​​​,​​'}'​​​,​​'['​​​,​​']'​​​ 的字符串​​s​​,判断字符串是否有效。有效字符串需满足:......
  • one preparation of algorithms in short text clustering
    文本聚类算法文本聚类一般步骤文本表示(TextRepresentation)把文档表示成聚类算法可以处理的形式。聚类算法选择或设计(ClusteringAlgorithms)算法的选择,往往伴随着相......
  • Go语言错误总结(三)
    15、Strings无法修改尝试使用索引操作来更新字符串变量中的单个字符将会失败。string是只读的byteslice(和一些额外的属性)。如果你确实需要更新一个字符串,那么使用byteslic......
  • Go语言错误总结(二)
    8、使用“nil”SlicesandMaps在一个nil的slice中添加元素是没问题的,但对一个map做同样的事将会生成一个运行时的panic。正确代码:packagemainfuncmain(){vars[]i......
  • P7962 [NOIP2021] 方差
    [NOIP2021]方差时隔一年。我又回来做这个题了。。。我们通过观察是可以发现这里的操作实际上就是交换相邻差分,但是差分\(c_1\)不可被交换。然后如果要求方差最小的话......
  • Java 通过IDEA连接sqlserver2012数据库
    1、官网下载sqlserver的jdbc在这里下载:http://www.microsoft.com/zh-cn/download/details.aspx?id=117744.0版本支持的 SQLServer有:Microsoft®SQLServer®2012Mi......