元春 發表於 2019-8-18 11:56:00

Go ---- defer 和 return 执行的先后顺序

<h3>Go 中 defer 和 return 执行的先后顺序</h3>
<ol>
<li>
<p>多个defer的执行顺序为“后进先出”;</p>
</li>
<li>
<p>defer、return、返回值三者的执行逻辑应该是:return最先执行,return负责将结果写入返回值中;接着defer开始执行一些收尾工作;最后函数携带当前返回值退出。</p>
</li>
</ol>
<p>&nbsp;</p>
<p>如果函数的返回值是无名的(不带命名返回值),则go语言会在执行return的时候会执行一个类似创建一个临时变量作为保存return值的动作,而有名返回值的函数,由于返回值在函数定义的时候已经将该变量进行定义,在执行return的时候会先执行返回值保存操作,而后续的defer函数会改变这个返回值(虽然defer是在return之后执行的,但是由于使用的函数定义的变量,所以执行defer操作后对该变量的修改会影响到return的值<br><br></p>
<p>eg1:不带命名返回值的函数</p>
<div class="cnblogs_Highlighter">
<pre class="brush:go;gutter:true;">package main

import "fmt"

func main() {
        fmt.Println("return:", test())// defer 和 return之间的顺序是先返回值, i=0,后defer
}

func test() int {//这里返回值没有命名
        var i int
        defer func() {
                i++
                fmt.Println("defer1", i) //作为闭包引用的话,则会在defer函数执行时根据整个上下文确定当前的值。i=2
        }()
        defer func() {
                i++
                fmt.Println("defer2", i) //作为闭包引用的话,则会在defer函数执行时根据整个上下文确定当前的值。i=1
        }()
        return i
} </pre>
</div>
<p>test() 先返回 i=0</p>
<p>defer2先于defer1执行</p>
<p>输出结果为:</p>
<p>defer2 1</p>
<p>defer1 2</p>
<p>return: 0</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>eg2:带命名返回值的函数:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:go;gutter:true;">package main

import "fmt"

func main() {
        fmt.Println("return:", test())
}

func test() (i int) { //返回值命名i
        defer func() {
                i++
                fmt.Println("defer1", i)
        }()
        defer func() {
                i++
                fmt.Println("defer2", i)
        }()
        return i
}
</pre>
</div>
<pre class="hljs undefined"><code class="hljs go">对外部变量的引用</code><code class="hljs go">作为函数参数(i),则在<span class="hljs-keyword">defer申明时就把值传递给<span class="hljs-keyword">defer,</span></span></code></pre>
<p> </p>
<p> 输出结果为:</p>
<p>defer2 1</p>
<p>defer1 2</p>
<p>return: 2</p>
<h1>理解return 返回值的运行机制:</h1>
<p>为了弄清上述两种情况的区别,我们首先要理解return 返回值的运行机制:<br>                        return 并非原子操作,分为赋值,和返回值两步操作<br>                        eg1 : 实际上return 执行了两步操作,因为返回值没有命名,所以<br>                        return 默认指定了一个返回值(假设为s),首先将i赋值给s,后续<br>                        的操作因为是针对i,进行的,所以不会影响s, 此后因为s不会更新,所以<br>                        return s 不会改变<br>                                相当于:<br>                                        var i int<br>                                        s := i<br>                                        return s<br>                        eg2 : 同上,s 就相当于 命名的变量i, 因为所有的操作都是基于<br>                                命名变量i(s),返回值也是i, 所以每一次defer操作,都会更新<br>                                返回值i<br><br></p>
<p> </p>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/saryli/p/11371912.html
頁: [1]
查看完整版本: Go ---- defer 和 return 执行的先后顺序