欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

Golang——延迟调用defer

发布时间:2025/3/15 编程问答 23 豆豆
生活随笔 收集整理的这篇文章主要介绍了 Golang——延迟调用defer 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

defer用于向当前函数注册稍后执行的函数调用。这些调用被称作延迟调用,它们直到当前函数执行结束前才被执行,常用于资源释放、错误处理等操作

func main() {f, err := os.Open("/test.txt")if err != nil {fmt.Println("os.Open err:", err)return}defer f.Close() // 仅注册,直到main退出前才执行 }

延迟调用注册的是调用,不是函数,需提供执行所需参数。参数值在注册时被赋值并缓存起来,如此状态敏感,可改用指针或闭包。延迟函数返回值会被抛弃

func main() {x, y := 1, 2defer func(a int) {println("defer x, y = ", a, y) // 为闭包引用}(x) // 注册时复制调用参数x += 100 // 对x的修改,不会影响延迟调用y += 200println(x, y) }

输出:

101 202 defer x, y = 1 202

多个延迟注册按FILO次序执行

func main() {defer println("a")defer println("b") }

输出:

b a

编译器通过在ret指令前插入指令来实现延迟调用执行,而return和panic语句都会终止 当前函数流程,弓I发延迟调用°return不是ret,它会更新返回值

func main() {println("test:", test()) }func test() (z int) {defer func() {println("defer:", z)z += 100 // 修改命名返回值}()return 100 // 实际执行次序:z = 100, call defer, ret }

输出:

defer: 100 test: 200

千万记住,延迟调用是在函数结束时才被执行。不合理的使用方式会浪费更多的资源,甚 至造成逻辑错误。

案例:循环处理多个日志文件,defer导致文件关闭时机延长

func main() {for i := 0; i < 10000; i++ {path := fmt.Sprintf("./log/%d.txt", i)f, err := os.Open(path)if err != nil {log.Println(err)continue}defer f.Close()// 这个关闭操作在main函数结束时才会执行,而不是当前循环。// 延长了逻辑结束时间和f生命周期,平白多消耗了内存等资源。 // 编译器也会提醒:可能发生资源泄漏,在 'for' 循环中调用 'defer' } }

应该直接调用,或重构为函数,让循环和处理算法分离

func main() {//日志处理算法。do := func(n int) {path := fmt.Sprintf("./log/%d.txt", n)f, err := os.Open(path)if err != nil {log.Println(err)return}defer f.Close() // 该延迟调用在此匿名函数结束时执行,而非main}for i := 0; i < 10000; i++ {do(i)} }

相比直接用CALL指令调用函数,延迟调用则需花费更大代价。这其中包括注册、调用等 操作,还有额外的缓存开销。相差几倍的结果足以引起重视。尤其是那些性能要求高且压力大的算法,应避免使用

总结

以上是生活随笔为你收集整理的Golang——延迟调用defer的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。