【Go面试向】defer与return的执行顺序初探

defer与return常考点

简述 defer 和 return 返回值 的执行顺序?如果要返回一个 defer 执行后的值, 可以通过哪些方式?

大家好 我是寸铁👊
总结了一篇defer 和 return 返回值 的执行顺序探讨的文章✨
喜欢的小伙伴可以点点关注 💝

程序1

不返回具体变量

执行顺序:
进入test函数

  1. 先把返回的结果赋值
  2. 执行defer函数
  3. 如果说defer函数中存在打印输出的内容,则先输出defer语句的内容。
    按照指定的顺序输出,后进先出的顺序输出
  4. 再返回到主函数main中,把之前赋值的返回的结果输出来

注意:return的结果是不会受defer函数而影响的,但是假如在defer外return之前进行赋值
则会返回当前更新的值。

demo


func Test() int {
   
    a := 1
    defer func() {
   
        fmt.Println("a", a) // a 1 
        a = 4
        fmt.Println("2", a) // 2 4
    }()
    return a // 1
}
func main() {
   
    fmt.Println(Test
<think>嗯,用户想了解Go语言中defer语句的执行顺序。我记得defer是延迟执行,但具体顺序是怎样的呢?根据之前看到的资料,多个defer好像是先进后出的顺序,也就是后进先出。比如引用里的例子,先调用的defer会最后执行。比如引用2中的例子,三个defer func1、func2、func3,实际执行顺序是func3先,然后func2,最后func1。这说明defer语句的执行顺序是逆序的,类似栈的结构。 然后,用户可能还关心defer在函数返回时的行为。比如有名返回值和匿名返回值的情况。根据引用5的例子,当函数返回的是命名变量时,defer中对变量的修改会影响最终的返回值。例如Demo2函数返回i,在defer中i被两次增加,所以最终返回的是2。而如果是匿名返回值,defer中的修改可能不会影响返回值,因为返回的是当时的值,而defer是在return之后执行。不过可能要看具体情况,比如是否在defer中修改了指针或者有副作用。 还有panic的情况,引用3提到,当遇到panic时,已经注册的defer执行,但panic之后的defer不会注册。比如例子中defer3在panic之后,所以不会执行,而defer1和defer2会按照后进先出的顺序执行。这说明在函数异常退出时,defer仍然会执行,但只有在panic之前注册的才会被执行。 另外,defer执行时机是在函数返回之前,但具体是在return之后还是之前呢?引用4提到在return语句之后执行,但可能要看return执行步骤。比如return语句可能先赋值给返回值变量,然后执行defer,最后函数返回。因此,如果返回值是命名变量,defer中对变量的修改会生效,而匿名变量则可能不会。 总结一下,defer执行顺序是后进先出,无论正常返回还是panic都会执行已注册的defer。有名返回值会被defer修改,而匿名返回值可能不会。此外,panic后的defer不会执行。需要把这些点整理清楚,用例子和引用支持回答。</think>### Go语言中defer语句执行顺序解析 #### 1. **基本执行顺序:后进先出(LIFO)** 在函数中,多个`defer`语句的执行顺序遵循**栈的规则**,即最后声明的`defer`最先执行,最先声明的`defer`最后执行。 例如: ```go func main() { defer fmt.Println("First deferred call") // 第三个执行 defer fmt.Println("Second deferred call") // 第二个执行 defer fmt.Println("Third deferred call") // 第一个执行 } // 输出: // Third deferred call // Second deferred call // First deferred call ``` 这一特性来源于`defer`的压栈机制[^2][^4]。 --- #### 2. **defer函数返回值的交互** - **匿名返回值**:`defer`中对返回值的修改**不会生效**,因为返回值在`return`时已确定。 例如: ```go func Demo1() int { i := 0 defer func() { i++ }() return i // 返回0 } ``` - **有名返回值**:`defer`中对命名返回值的修改**会生效**,因为返回值是变量本身。 例如: ```go func Demo2() (i int) { defer func() { i++ }() return i // 最终返回1 } ``` 这里`defer`在`return`之后执行,但修改了命名返回值变量`i`[^5]。 --- #### 3. **deferpanic/return执行顺序** - **正常返回**:`defer`在`return`**之后**执行,但会**先处理返回值,再执行`defer`**。 - **触发panic**:已注册的`defer`仍会执行,但`panic`后的`defer`不会注册。 例如: ```go func main() { defer fmt.Println("defer1") // 执行 defer fmt.Println("defer2") // 执行 panic("发生异常") defer fmt.Println("defer3") // 未注册 } // 输出: // defer2 // defer1 // panic信息 ``` 说明`panic`会中断后续代码,但已注册的`defer`仍按LIFO执行[^3]。 --- #### 4. **总结规则** 1. **执行顺序**:后进先出(LIFO)。 2. **返回值影响**:仅对命名返回值生效。 3. **异常处理**:`panic`前注册的`defer`会执行。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

寸 铁

感谢您的支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值