Golang | 面试题每日一练 (1)
💢欢迎来到张胤尘的技术站
💥技术如江河,汇聚众志成。代码似星辰,照亮行征程。开源精神长,传承永不忘。携手共前行,未来更辉煌💥
文章目录
- Golang | 每日一练 (1)
- 题目
- 参考答案
Golang | 每日一练 (1)
题目
golang
中 defer
语句的执行顺序是如何定义的?请说明 defer
与函数返回值之间的交互机制。
参考答案
在 golang
中,defer
用于延迟执行函数调用,直到包含它的函数返回时才执行。
defer
语句的执行顺序遵循 后进先出(LIFO) 原则,即最后声明的 defer
会最先执行。
例如:
package main
import "fmt"
func main() {
// 输出顺序为:
// main function
// defer 2
// defer 1
defer fmt.Println("defer 1")
defer fmt.Println("defer 2")
fmt.Println("main function")
}
由以上代码示例中可以看出,defer
的执行顺序与声明顺序是相反的。
由于 defer
的执行时机在 return
之后,但在返回值被传递给调用者之前。这也就是说 defer
可以修改返回值,具体的修改时机有如下两种情况:
- 无命名返回值
如果函数的返回值没有命名,defer
无法修改返回值。例如:
package main
import "fmt"
func test() int {
var i int
defer func() {
i++
}()
return i
}
func main() {
ret := test()
fmt.Println(ret) // 0
}
在 main
函数中调用了 test
函数并进行结果的输出,观察到输出的结果为0,使用 defer
后并没有修改 i
返回值的结果。
当函数返回值没有命名时,return
会将函数栈中的变量值拷贝到调用栈的临时变量中,然后执行 defer
。defer
修改的是函数栈中的变量,而不是调用栈的临时变量。因此,defer
的修改不会影响最终的返回值。
- 命名返回值
当函数返回值有命名时,情况会有所不同。defer
可以直接修改这个变量的值,最终影响返回值。例如:
package main
import "fmt"
func test() (i int) {
defer func() {
i++
}()
return i
}
func main() {
ret := test()
fmt.Println(ret) // 1
}
在 golang
中,命名返回值不仅仅是语法糖,它实际上是一个在函数作用域内声明的变量。这意味着命名返回值在函数的整个生命周期内都是可访问和可修改的。
执行流程分析:
-
当声明一个命名返回值
func test() (i int)
时,golang
会在函数的作用域内声明一个变量i
,并将其初始化为0
(int
类型的零值)。 -
在
golang
中,return
的行为是将命名返回值的当前值标记为要返回的值,但并不会立即返回。此时,命名返回值i
的值会被“标记”为返回值,但实际的返回操作还没有完成。 -
defer
会在函数返回之前执行,但它的执行时机是在return
将返回值标记之后,但在实际返回操作完成之前。这意味着defer
可以访问和修改命名返回值i
。 -
在
defer
中,可以直接修改命名返回值i
,因为i
是函数作用域内的变量,defer
可以访问和修改它。这种修改会影响最终返回的值。
最终在 defer
执行完成后,函数才会将命名返回值的实际值返回给调用者。因此,defer
中对命名返回值的修改会直接影响最终的返回值。
🌺🌺🌺撒花!
如果本文对你有帮助,就点关注或者留个👍
如果您有任何技术问题或者需要更多其他的内容,请随时向我提问。