原文链接:https://studygolang.com/articles/4809

Go语言中延迟函数defer充当着 cry...catch 的重任,使用起来也非常简便,然而在实际应用中,很多gopher并没有真正搞明白defer、return和返回值之间的执行顺序,从而掉进坑中,今天我们就来揭开它的神秘面纱!

先来运行下面两段代码:

A. 无名返回值的情况

package main

import (
"fmt"
) func main() {
fmt.Println("return:", a()) // 打印结果为 return: 0
} func a() int {
var i int
defer func() {
i++
fmt.Println("defer2:", i) // 打印结果为 defer: 2
}()
defer func() {
i++
fmt.Println("defer1:", i) // 打印结果为 defer: 1
}()
return i
}

B. 有名返回值的情况

package main

import (
"fmt"
) func main() {
fmt.Println("return:", b()) // 打印结果为 return: 2
} func b() (i int) {
defer func() {
i++
fmt.Println("defer2:", i) // 打印结果为 defer: 2
}()
defer func() {
i++
fmt.Println("defer1:", i) // 打印结果为 defer: 1
}()
return i // 或者直接 return 效果相同
}

先来假设出结论,帮助大家理解原因:

  1. 多个defer的执行顺序为“后进先出”;

  2. defer、return、返回值三者的执行逻辑应该是:return最先执行,return负责将结果写入返回值中;接着defer开始执行一些收尾工作;最后函数携带当前返回值退出。

如何解释两种结果的不同:

上面两段代码的返回结果之所以不同,其实从上面第2条结论很好理解。

a()int 函数的返回值没有被提前声名,其值来自于其他变量的赋值,而defer中修改的也是其他变量,而非返回值本身,因此函数退出时返回值并没有被改变。

b()(i int) 函数的返回值被提前声名,也就意味着defer中是可以调用到真实返回值的,因此defer在return赋值返回值 i 之后,再一次地修改了 i 的值,最终函数退出后的返回值才会是defer修改过的值。

C. 下面我们再来看第三个例子,验证上面的结论:

package main

import (
"fmt"
) func main() {
fmt.Println("c return:", *(c())) // 打印结果为 c return: 2
} func c() *int {
var i int
defer func() {
i++
fmt.Println("c defer2:", i) // 打印结果为 c defer: 2
}()
defer func() {
i++
fmt.Println("c defer1:", i) // 打印结果为 c defer: 1
}()
return &i
}

虽然 c()*int 的返回值没有被提前声明,但是由于 c()*int 的返回值是指针变量,那么在return将变量 i 的地址赋给返回值后,defer再次修改了 i 在内存中的实际值,因此函数退出时返回值虽然依旧是原来的指针地址,但是其指向的内存实际值已经被成功修改了。

即,我们假设的结论是正确的!

Golang中defer、return、返回值之间执行顺序的坑的更多相关文章

  1. go中defer的理解--defer、return、返回值之间执行顺序

    defer可以读取有名返回值 func c() (i int) { defer func() { i++ }() return 1 } 输出结果是2. 在开头的时候,我们知道defer是在return ...

  2. C++中的return返回值:return0 or return -1?

    C++98 中定义了如下两种 main 函数的定义方式: int main( ) int main( int argc, char *argv[] )   (参考资料:ISO/IEC 14882(19 ...

  3. 用jquery的ajax方法获取不到return返回值

    如果jquery中,获取不到ajax返回值. 两个错误写法会导致这种情况:1.ajax未用同步 2.在ajax方法中直接return返回值. 下面列举了三种写法,如果想成功获取到返回值,参考第三种写法 ...

  4. $.ajax() 获取不到return 返回值

    /*常见错误示例 直接在 ajax 里面return 结果 */ function demo(){ $.ajax({ url : 'test.do', type : "post", ...

  5. try--catch--finally中return返回值执行的顺序(区别)

    1.try块中没有抛出异常,try.catch和finally块中都有return语句 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public static int ...

  6. try--catch--finally中return返回值执行的顺序

    1.try块中没有抛出异常,try.catch和finally块中都有return语句 public static int NoException(){ int i=10; try{ System.o ...

  7. 延宕执行,妙用无穷,Go lang1.18入门精炼教程,由白丁入鸿儒,Golang中defer关键字延迟调用机制使用EP17

    先行定义,延后执行.不得不佩服Go lang设计者天才的设计,事实上,defer关键字就相当于Python中的try{ ...}except{ ...}finally{...}结构设计中的finall ...

  8. javascript中的函数返回值(return)

    有些情况,我们希望获取到函数的执行结果,也就是我们需要在函数以外的地方处理执行结果,而不是在函数内部处理.这时我们就需要为函数设一个返回值,也就是return,即函数执行完毕以后返回的结果. 若在函数 ...

  9. 关于ExecuteNonQuery执行存储过程的返回值 、、实例讲解存储过程的返回值与传出参数、、、C#获取存储过程的 Return返回值和Output输出参数值

    关于ExecuteNonQuery执行存储过程的返回值 用到过ExecuteNonQuery()函数的朋友们在开发的时候肯定这么用过. if(cmd.ExecuteNonQuery("xxx ...

随机推荐

  1. Chrome 性能监测

    前端性能优化一直是前端工作中必不可少的一部分,但是我们如何知道哪些部分的性能有优化的空间呢?此时,Chrome 性能监测就派上用场了. 正所谓:知己知彼,百战百胜,只有确定了性能瓶颈,才能有条不紊地进 ...

  2. margin显示怪异,外边距合并问题

    很多时候我们使用两个div,内层的div设置文字,需要垂直居中与上层div,但是怎么设置样式都不行,vertical-align:middle也不行. 代码: <div style=" ...

  3. Tomcat上发布webservices的war工程,访问异常404

    Tomcat上发布webservices的war工程,访问异常404 Tomcat部署正常.war导出工程正常.Tomcat自带的工程可以正常访问: 问题: webservices工程访问异常404 ...

  4. Android JSON 解析关键代码

    Android Json 解析其实还是蛮重要的知识点,为什么这么说呢,因为安卓通信大部分的协议都是使用 json 的方式传输,我知道以前大部分是使用的 xml ,但是时代在发展社会在进步,json 成 ...

  5. 20145104张家明 《Java程序设计》第四次实验设计

    20145104张家明 <Java程序设计>第四次实验设计 这第四次实验报告 我们开始着手安卓了 在电脑上安装了安卓虚拟机

  6. Android 实践项目开发 总结

      Android 实践项目开发 总结 课程:移动平台应用开发实践  班级:201592  姓名:杨凤  学号:20159213 成绩:___________       指导老师:娄嘉鹏       ...

  7. UVa 10285 Longest Run on a Snowboard - 记忆化搜索

    记忆化搜索,完事... Code /** * UVa * Problem#10285 * Accepted * Time:0ms */ #include<iostream> #includ ...

  8. P1471 方差

    题目 luogu 思路 \[\frac{1}{n}*\sum_{1}^{n}( a_{i}-A)^{2}\] \[\frac{1}{n}*\sum_{1}^{n}( a_{i}^2-2*A*a_{i} ...

  9. 小朋友排队|2014年蓝桥杯B组题解析第十题-fishers

    小朋友排队 n 个小朋友站成一排.现在要把他们按身高从低到高的顺序排列,但是每次只能交换位置相邻的两个小朋友. 每个小朋友都有一个不高兴的程度.开始的时候,所有小朋友的不高兴程度都是0. 如果某个小朋 ...

  10. hdu 6180 Schedule

    Schedule Problem Description There are N schedules, the i-th schedule has start time si and end time ...