Go--使用defer的陷阱

本文探讨了Go语言中defer的关键字使用,强调了它在文件关闭、资源解锁和数据库连接关闭等场景的重要性。通过小测试和示例解析,详细解释了defer执行顺序、参数求值时序以及在函数返回值影响上的特点,揭示了defer可能导致的陷阱和需要注意的细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Go—–使用defer的陷阱
defer关键字用来推迟执行某个语句或函数到任意位置执行return语句之后。常用在:文件流的关闭、解锁一个加锁的资源、关闭数据库链接等。函数中存在defer语句时的执行顺序是:先return后执行defer语句,最后才结束函数调用。以下面几个测试作为例子进行讲解。

小测试

下面的几个test结果会是多少呢?先自己思考下结果,答案在文章后面。
teet1

package main

import "fmt"

func main() {
    i := 0
    defer fmt.Println(i)
    i++
    return
}

test2

package main

import "fmt"

func main() {
    fmt.Println(test())
}

func test() (result int) {
    defer func() {
        result++
    }()
    return 0
}

test3

package main

import "fmt"

func main(){    
    arr := [5]string{"Go", "Java", "JavaScript", "c++", "Python"}
    for _, value := range arr {
        defer  fmt.Printf("%s -->",value)
    }
    fmt.Println("从我开始执行")
}

test4

package main

import "fmt"

func main() {
    arr := [5]string{"Go", "Java", "JavaScript", "c++", "Python"}
    for _, value := range arr {
        defer func() {
            fmt.Printf("%s -->",value)
        }()
    }
    fmt.Println("从我开始执行")
}

test5

package main

import "fmt"

func main() {
    i:=0
    defer func(i int) {
        for ;i<5 ; i++ {
            fmt.Printf("%d -->",i)
        }
    }(i)
    i++
}
defer示例答案及原理解析

test1答案
结果为“0”,而不是“1”。原因在Go文档中有对defer的解释:Each time a “defer” statement executes, the function value and parameters to the call are evaluated as usual and saved a new, but the actual function is not invoked。
也就是说在程序还没运行defer的函数之前,传入函数的参数值已经得到了保存,只是没有调用而已。因此,打印函数中的参数i值为0,而不是加1后的值。
test2答案
运行结果为1,而不是0。原因是defer语句是在return语句之前执行的,而且return语句不是原子的。“return XXX”语句其实可以改写成两句:

result = 1
return

因此函数返回的实际过程是这样的:先给返回值赋值,然后调用defer表达式,最后才是返回到调用函数中。defer表达式可能会在设置函数返回值之后,在返回到调用函数之前,修改返回值,使最终的函数返回值与你想象的不一致。
test3答案
运行结果为

从我开始执行
Python -->c++ -->JavaScript -->Java -->Go -->

原因在于当有多个defer被注册时,它们会以出栈的顺序执行。
test4答案
运行结果为

从我开始执行
Python -->Python -->Python -->Python -->Python -->

原因在于defer函数执行时,for循环已经结束,此时的value为最后一次循环的值,即Python,因此,当执行defer函数时,只是对Python的循环打印。
test5答案
运行结果为”0 –>1 –>2 –>3 –>4 –>“,而不是”1 –>2 –>3 –>4 –>“,具体原因和test1的原理一样,在匿名函数中传入的参数i在defer函数未执行之前,就已经得到了保存。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值