Golang中两种不同结果的defer打印方式解析
Golang中两种不同结果的defer打印方式解析
大家好,我是Go语言的初学者,我发现使用这两种defer语句会产生不同的结果。以下是我的代码。
调用 1
func TestDefer(t *testing.T) {
var test string
defer t.Log(test)
test = "hello"
}
调用 2
func TestDefer(t *testing.T) {
var test string
defer func() {
t.Log(test)
}()
test = "hello"
}
有人可以解释一下这种差异背后的原因吗?
更多关于Golang中两种不同结果的defer打印方式解析的实战教程也可以访问 https://www.itying.com/category-94-b0.html
当延迟函数是一个闭包时,t.Log() 的参数直到闭包执行时才会被求值。
以下是你的答案:
Go 语言的 “defer” 如何捕获闭包的参数?
标签: go, closures
… 以及来自官方文档的内容:
每次执行 “defer” 语句时,函数值和调用参数会像往常一样被求值并重新保存,但实际的函数并不会被调用。
因此,在第二个例子中通过添加一层间接性,只有外层函数在你将其添加到栈时被求值(而不是对 t.Log 的调用)。作为一名 Go 语言新手,谨慎/深思熟虑地使用 defer 语句(以及 goroutine 中类似的陷阱!)是很好的习惯。
在Go语言中,defer语句对参数的求值时机是造成这两种情况差异的关键。
调用1:defer t.Log(test) 在声明时立即对 test 进行求值,此时 test 的值为空字符串 ""。延迟执行的是 t.Log("")。
调用2:defer func() { t.Log(test) }() 中的匿名函数形成了一个闭包,它捕获的是变量 test 本身,而不是当前值。当延迟函数执行时,它访问的是已经更新为 "hello" 的 test 变量。
示例代码可以更清晰地展示这一区别:
package main
import "fmt"
func case1() {
var test string
defer fmt.Println("Case1:", test) // test 的值在此刻被求值并绑定为 ""
test = "hello"
}
func case2() {
var test string
defer func() {
fmt.Println("Case2:", test) // 闭包捕获了变量 test 的引用
}()
test = "hello"
}
func main() {
case1() // 输出: Case1:
case2() // 输出: Case2: hello
}
输出结果:
Case1:
Case2: hello
在第一个案例中,defer 的参数在语句执行时就被固定了。在第二个案例中,匿名函数体中的 test 在函数实际执行时才被解析,因此获得了最终的值。

