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

4 回复

谢谢

更多关于Golang中两种不同结果的defer打印方式解析的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


当延迟函数是一个闭包时,t.Log() 的参数直到闭包执行时才会被求值。

以下是你的答案:

stackoverflow.com

Go 语言的 “defer” 如何捕获闭包的参数?

标签: go, closures

… 以及来自官方文档的内容:

每次执行 “defer” 语句时,函数值和调用参数会像往常一样被求值并重新保存,但实际的函数并不会被调用。

因此,在第二个例子中通过添加一层间接性,只有外层函数在你将其添加到栈时被求值(而不是对 t.Log 的调用)。作为一名 Go 语言新手,谨慎/深思熟虑地使用 defer 语句(以及 goroutine 中类似的陷阱!)是很好的习惯。

在Go语言中,defer语句对参数的求值时机是造成这两种情况差异的关键。

调用1defer t.Log(test) 在声明时立即对 test 进行求值,此时 test 的值为空字符串 ""。延迟执行的是 t.Log("")

调用2defer 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 在函数实际执行时才被解析,因此获得了最终的值。

回到顶部