Go语言defer的延迟执行机制

您所在的位置:网站首页 go语言defer机制 Go语言defer的延迟执行机制

Go语言defer的延迟执行机制

2024-07-12 11:02| 来源: 网络整理| 查看: 265

1        题目(单选题)

如下Go语言程序的输出结果是()

package main

import "fmt"

func f1(name string) string {

    fmt.Println("in f1", name)

    return name

}

func f2(name string) string {

    fmt.Println("in f2", name)

    return name

}

func f3() {

    defer f2(f1("function"))

    fmt.Println("in f3 function")

}

func main() {

    f3()

}

in f1 functionin f3 functionin f2 function in f1 functionin f2 functionin f3 function in f3 functionin f1 functionin f2 function in f3 functionin f2 functionin f1 function 2        实际答题情况

正确答案 A。

各个选项的选择率为:

A

20.2%

B

0.8%

C

78.2%

D

0.8%

3        知识点解读

defer 是 Go 语言中用于延迟执行函数调用的关键字,defer 语句主要包括下面这些知识点:

1)   延迟执行

defer语句会将紧跟其后的函数调用推迟到包含该defer语句的函数返回前执行。

这个特性使得程序员可以在不改变函数逻辑的情况下,确保在函数结束时执行特定操作。

例如:

package main

 

import "fmt"

 

func main() {

    defer cleanUp()

    fmt.Println("hello")

}

func cleanUp() {

    fmt.Println("world")

}

运行结果为:

hello

world

2)   执行顺序

如果在一个函数中有多个defer语句,会按照后进先出(LIFO,Last In First Out)的原则执行,即最后声明的defer函数最先被执行,以此类推直至所有的defer函数都被执行完毕。举个例子:

package main

 

import "fmt"

 

func add(a, b int) {

    fmt.Println("Result =", a + b)

}

 

func main() {

    fmt.Println("Begin")

    defer fmt.Println("End")

    defer add(36, 64)

    defer add(2, 8)

}

运行结果:

Begin

Result = 10

Result = 100

End

3)   与return配合使用

当 defer 与 return 同时存在时,先执行return语句,再执行defer语句。

下面例子演示了defer 与 return 执行的先后顺序:

package main

 

import "fmt"

 

func deferFunc() {

    fmt.Println("defer func called")

}

 

func returnFunc() int {

    fmt.Println("return func called")

    return 0

}

 

func returnAndDefer() int {

    defer deferFunc()

    return returnFunc()

}

 

func main() {

    returnAndDefer()

}

输出结果:

return func called

defer func called

可以看到,return 后面的语句先执行,defer 后面的语句后执行

4)   函数参数的值

在 defer 声明时,函数的参数会立即求值并被保存,但实际调用会延迟到包含 defer 语句的函数即将返回时执行。

package main

 

import "fmt"

 

func printIndex(index int, _ int) int {

    fmt.Print(index)

    return index

}

 

func main() {

    defer printIndex(1, printIndex(3, 0))

    defer printIndex(2, printIndex(4, 0))

}

这里有 4 次函数调用,index 分别为 1,2,3,4。

那么这 4 次函数的先后执行顺序是什么呢?这里面有两个 defer 语句, 所以 defer 一共会压栈两次:先压 printIndex(1, printIndex(3, 0)),后压 printIndex(2, printIndex(4, 0))。

在压栈 printIndex(1, printIndex(3, 0)) 的时候,需要连同函数地址、函数形参一同进栈,为了得到 printIndex(1, printIndex(3, 0)) 的第二个参数的结果,所以需要先执行printIndex(3, 0)将第二个参数算出,于是 printIndex(3, 0) 就被第一个执行。

同理压栈 printIndex(2, printIndex(4, 0)),需要执行 printIndex(4, 0),于是 printIndex(4, 0) 就被第二个执行。

执行顺序如下:

(1)    defer 压栈 printIndex(1, printIndex(3, 0)),压栈函数地址、形参 1、形参 2 (调用 printIndex(3, 0)) –> 打印 3

(2)    defer 压栈 printIndex(2, printIndex(4, 0)),压栈函数地址、形参 1、形参 2 (调用 printIndex(4, 0)) –> 打印 4

(3)    defer 出栈 printIndex(2, printIndex(4, 0)), 调用 printIndex2 –> 打印 2

(4)    defer 出栈 printIndex(1, printIndex(3, 0)), 调用 printIndex1 –> 打印 1

最终输出结果:3421

5)   匿名函数

defer 延迟执行时,如果函数调用中使用了匿名函数或闭包,它们可能会对外部变量产生影响,因为它们保留了对外部变量的引用,例如:

package main

 

import "fmt"

 

func returnButDefer() (t int) { // 命名返回值t初始化0, 并且作用域为该函数全域

    defer func() {

        t = t * 10

    }()

 

    return 1

}

 

func main() {

    fmt.Println(returnButDefer())

}

returnButDefer()原本应该返回1,但是在 return 之后,又被 defer 的匿名 func 函数执行,所以 t = t * 10 被执行,最后 returnButDefer() 返回给上层 main() 的结果为 10

输出结果:10

4        题目解析

我们来分析题目中f3函数中defer语句的执行过程:

(1)当f3函数执行到defer语句时,会先执行f1("function")这个函数调用;所以,"in f1 function"会首先被打印出来。

这是因为“在 defer 声明时,函数的参数会立即求值并被保存”。

(2)然后,f1函数会返回name这个字符串(内容为"function")。

(3)接着,defer语句会将f2(f1("function"))这个函数调用延迟到f3函数执行完毕之后再执行。

(4)最后,f3函数会打印出"in f3 function"。然后,defer语句中延迟的函数调用f2(f1("function"))会被执行。最后"in f2 function"会被打印出来。

因此,这段程序的输出结果是:

A.

in f1 function

in f3 function

in f2 function

这个题目涉及到了Go语言中defer语句的执行时机以及函数调用的顺序;通过这个案例,我们可以更好地理解了defer语句的作用和函数调用的执行顺序。

5        总结

defer 是在 Go 语言中确保清理工作执行的一种机制,常用于资源释放,如文件关闭、锁的释放、数据库连接的关闭等。它保证这些清理工作在函数执行结束后执行,有效地预防了因忘记释放资源而导致的问题。

这个特性使得 defer 在资源管理非常有用,通过延迟执行,它确保了资源的及时释放。然而,过度使用 defer 可能增加代码的复杂性和内存消耗,因此需要谨慎使用,避免滥用。

6        推荐学习资料

Go语言官方文档:

https://go.dev/blog/defer-panic-and-recover

https://medium.com/codex/what-do-you-need-to-know-about-golangs-defer-4fac71e0f00b

本文来自博客园,作者:易先讯,转载请注明原文链接:https://www.cnblogs.com/gongxianjin/p/17961278



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3