教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 Go: defer与return小记

Go: defer与return小记

发布时间:2022-01-06   编辑:jiaochengji.com
教程集为您提供Go: defer与return小记等资源,欢迎您收藏本站,我们将为您提供最新的Go: defer与return小记资源
<h4>1 官方定义</h4>

A defer statement pushes a function call onto a list. The list of saved calls is executed after the surrounding function returns. Defer is commonly used to simplify functions that perform various clean-up actions.
defer表达式将一个函数调用保存在列表中,当包裹defer的函数"返回"后,列表中的调用会被执行。defer通常用于清理收尾工作。
<code>注意:这里的返回加了引号,原因如下</code>

<h4>2 实现逻辑</h4>

<code>参考 雨痕大神的读书笔记(https://github.com/qyuhen/book)源码第20章</code>
大致表达为:
step 1 : 在defer表达式的地方,会调用runtime.deferproc(size int32, fn *funcval)保存延时调用,注意这里保存了延时调用的参数
step 2 : 在return时,先将返回值保存起来
step 3 : 按FILO顺序调用runtime.deferreturn,即延时调用
step 4 : RET指令

因此,return并不是一个原子操作,函数返回值可能与你的预期不一样。

<h4>3 避坑提示</h4> <h6>1. defer的参数在声明时即被确定下来,先看个例子(生产环境这样写估计会被唾沫喷死)</h6> <pre><code class="lang-Go hljs">func calc(index string, a, b int) int { ret := a b fmt.Println(index, a, b, ret) return ret } func main() { a := 1 b := 2 defer calc("1", a, calc("10", a, b)) a = 0 defer calc("2", a, calc("20", a, b)) b = 1 } </code></code></pre>

输出结果为:

<pre><code class="lang-go hljs">10 1 2 3 20 0 2 2 2 0 2 2 1 1 3 4 </code></code></pre>

原因是defer calc("1", a, calc("10", a, b)) 的第3个参数会在调用runtime.deferproc时确定,并不会在延时调用时才会被计算。

<h6>2. 有名与无名返回值</h6> <pre><code class="lang-Go hljs">func namedReturn() (r int) { defer func() { r fmt.Println("defer in namedReturn : r = ", r) }() return } func unnamedReturn() int { var r int defer func() { r fmt.Println("defer in unnamedReturn : r = ", r) }() return r } func main() { fmt.Println("namedReturn : r = ", namedReturn()) fmt.Println("unnamedReturn : r = ", unnamedReturn()) } </code></code></pre>

输出结果为:

<pre><code class="lang-go hljs">defer in namedReturn : r = 1 namedReturn : r = 1 defer in unnamedReturn : r = 1 unnamedReturn : r = 0 </code></code></pre>

原因就是return会将返回值先保存起来,对于无名返回值来说,保存在一个临时对象中,defer是看不到这个临时对象的;而对于有名返回值来说,就保存在已命名的变量中。

<h6>3. 延时参数与有名返回值遮蔽</h6> <pre><code class="lang-Go hljs">func ShelteredReturn() (r int) { defer func(r int) { r fmt.Println("defer in ShelteredReturn : r = ", r) }(r) return 0 } func main() { fmt.Println("ShelteredReturn : r = ", ShelteredReturn()) } </code></code></pre>

输出结果为:

<pre><code class="lang-go hljs">defer in ShelteredReturn : r = 1 ShelteredReturn : r = 0 </code></code></pre>

虽然r是有名返回值,但在defer func(r int)中的r是形参,与ShelteredReturn的返回值不是同一个。

<h4>参考文献</h4>

[1]. http://lib.csdn.net/article/go/33950
[2]. https://blog.golang.org/defer-panic-and-recover
[3]. https://my.oschina.net/henrylee2cn/blog/505535
[4]. https://github.com/qyuhen/book


到此这篇关于“Go: defer与return小记”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
Go: defer与return小记
Golang中defer关键字实现原理
Golang defer解读
Golang Defer详解
defer函数参数求值简要分析
go那些事儿|defer必掌握知识
Go 学习之路:异常处理defer,panic,recover
defer ,panic,recover
Golang defer 使用时的坑
Go 中 defer 的 5 个坑 - 第一部分

[关闭]
~ ~