教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 12. Go 语言流程控制:defer 延迟语句

12. Go 语言流程控制:defer 延迟语句

发布时间:2022-03-19   编辑:jiaochengji.com
教程集为您提供12. Go 语言流程控制:defer 延迟语句等资源,欢迎您收藏本站,我们将为您提供最新的12. Go 语言流程控制:defer 延迟语句资源

Hi,大家好,我是明哥。

在自己学习 Golang 的这段时间里,我写了详细的学习笔记放在我的个人微信公众号 《Go编程时光》,对于 Go 语言,我也算是个初学者,因此写的东西应该会比较适合刚接触的同学,如果你也是刚学习 Go 语言,不防关注一下,一起学习,一起成长。

<blockquote>我的在线博客:http://golang.iswbm.com
我的 Github:github.com/iswbm/GolangCodingTime</blockquote>

Go里的流程控制方法还是挺丰富,整理了下有如下这么多种:

<ul><li>if - else 条件语句</li> <li>switch - case 选择语句</li> <li>for - range 循环语句</li> <li>goto 无条件跳转语句</li> <li>defer 延迟执行</li> </ul>

今天是最后一篇讲控制流程了,内容是 defer 延迟语句,这个在其他编程语言里好像没有见到。应该是属于 Go 语言里的独有的关键字,但即使如此,阅读后这篇文章后,你可以发现 defer 在其他编程语言里的影子。

<h2>1. 延迟调用</h2>

defer 的用法很简单,只要在后面跟一个函数的调用,就能实现将这个 <code>xxx</code> 函数的调用延迟到当前函数执行完后再执行。

<pre><code class="go">defer xxx() </code></pre>

这是一个很简单的例子,可以很快帮助你理解 defer 的使用效果。

<pre><code class="go">import "fmt" func myfunc() { fmt.Println("B") } func main() { defer myfunc() fmt.Println("A") }</code></pre>

输出如下

<pre><code>A B</code></pre>

当然了,对于上面这个例子可以简写为成如下,输出结果是一致的

<pre><code class="go">import "fmt" func main() { defer fmt.Println("B") fmt.Println("A") }</code></pre> <h2>2. 即时求值的变量快照</h2>

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

比如这边的例子

<pre><code class="go">import "fmt" func main() { name := "go" defer fmt.Println(name) // 输出: go name = "python" fmt.Println(name) // 输出: python }</code></pre>

输出如下,可见给 name 重新赋值为 <code>python</code>,后续调用 defer 的时候,仍然使用未重新赋值的变量值,就好在 defer 这里,给所有的这是做了一个快照一样。

<pre><code>python go</code></pre> <h2>3. 多个defer 反序调用</h2>

当我们在一个函数里使用了 多个defer,那么这些defer 的执行函数是如何的呢?

做个试验就知道了

<pre><code class="go">import "fmt" func main() { name := "go" defer fmt.Println(name) // 输出: go name = "python" defer fmt.Println(name) // 输出: python name = "java" fmt.Println(name) }</code></pre>

输出如下,可见 多个defer 是反序调用的,有点类似栈一样,后进先出。

<pre><code>java python go</code></pre> <h2>3. defer 与 return 孰先孰后</h2>

至此,defer 还算是挺好理解的。在一般的使用上,是没有问题了。

在这里提一个稍微复杂一点的问题,defer 和 return 到底是哪个先调用?

使用下面这段代码,可以很容易的观察出来

<pre><code class="go">import "fmt" var name string = "go" func myfunc() string { defer func() { name = "python" }() fmt.Printf("myfunc 函数里的name:%s\n", name) return name } func main() { myname := myfunc() fmt.Printf("main 函数里的name: %s\n", name) fmt.Println("main 函数里的myname: ", myname) }</code></pre>

输出如下

<pre><code>myfunc 函数里的name:go main 函数里的name: python main 函数里的myname: go</code></pre>

来一起理解一下这段代码,第一行很直观,name 此时还是全局变量,值还是go

第二行也不难理解,在 defer 里改变了这个全局变量,此时name的值已经变成了 python

重点在第三行,为什么输出的是 go ?

解释只有一个,那就是 defer 是return 后才调用的。所以在执行 defer 前,myname 已经被赋值成 go 了。

<h2>4. 为什么要有 defer?</h2>

看完上面的例子后,不知道你是否和我一样,对这个defer的使用效果感到熟悉?貌似在 Python 也见过类似的用法。

虽然 Python 中没有 defer ,但是它有 with 上下文管理器。我们知道在 Python 中可以使用 defer 实现对资源的管理。最常用的例子就是文件的打开关闭。

你可能会有疑问,这也没什么意义呀,我把这个放在 defer 执行的函数放在 return 那里执行不就好了。

固然可以,但是当一个函数里有多个 return 时,你得多调用好多次这个函数,代码就臃肿起来了。

若是没有 defer,你可以写出这样的代码

<pre><code class="go">func f() { r := getResource() //0,获取资源 ...... if ... { r.release() //1,释放资源 return } ...... if ... { r.release() //2,释放资源 return } ...... if ... { r.release() //3,释放资源 return } ...... r.release() //4,释放资源 return }</code></pre>

使用了 defer 后,代码就显得简单直接,不管你在何处 return,都会执行 defer 后的函数。

<pre><code class="go">func f() { r := getResource() //0,获取资源 defer r.release() //1,释放资源 ...... if ... { ... return } ...... if ... { ... return } ...... if ... { ... return } ...... return }</code></pre>

系列导读

01. 开发环境的搭建(Goland & VS Code)

02. 学习五种变量创建的方法

03. 详解数据类型:整形与浮点型

04. 详解数据类型:byte、rune与string

05. 详解数据类型:数组与切片

06. 详解数据类型:字典与布尔类型

07. 详解数据类型:指针

08. 面向对象编程:结构体与继承

09. 一篇文章理解 Go 里的函数

10. Go语言流程控制:if-else 条件语句

11. Go语言流程控制:switch-case 选择语句

12. Go语言流程控制:for 循环语句

13. Go语言流程控制:goto 无条件跳转

14. Go语言流程控制:defer 延迟调用

15. 面向对象编程:接口与多态

16. 关键字:make 和 new 的区别?

17. 一篇文章理解 Go 里的语句块与作用域

18. 学习 Go 协程:goroutine

19. 学习 Go 协程:详解信道/通道

20. 几个信道死锁经典错误案例详解

21. 学习 Go 协程:WaitGroup

22. 学习 Go 协程:互斥锁和读写锁

23. Go 里的异常处理:panic 和 recover

24. 超详细解读 Go Modules 前世今生及入门使用

25. Go 语言中关于包导入必学的 8 个知识点

26. 如何开源自己写的模块给别人用?

27. 说说 Go 语言中的类型断言?

28. 这五点带你理解Go语言的select用法


<span class="img-wrap"></span>

到此这篇关于“12. Go 语言流程控制:defer 延迟语句”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
从零学习 Go 语言(12):流程控制之defer 延迟语句
Go语言之defer
go 学习笔记之咬文嚼字带你弄清楚 defer 延迟函数
defer,panic 和 Recover
Golang 学习笔记:流程控制
Go中defer的延迟调用
从零学习 Go 语言(24):理解 Go 语言中的 goroutine
12. Go 语言流程控制:defer 延迟语句
Go:defer 语句如何工作
图解 Go 中的延迟调用 defer

[关闭]
~ ~