在相同的结构体中,Golang中的for循环中的defer行为是不同的。

huangapple go评论84阅读模式
英文:

Golang defers in a for loop behaves differently for the same struct

问题

我写了以下的 Golang 代码并运行了它。

type Test struct {
	Name string
}

func (t Test) hello() {
	fmt.Printf("Hello, %s\n", t.Name)
}

func (t *Test) hello2() {
	fmt.Printf("pointer: %s\n", t.Name)
}

func runT(t Test) {
	t.hello()
}

func main() {
	mapt := []Test{
		{Name: "A"},
		{Name: "B"},
		{Name: "C"},
	}

	for _, t := range mapt {
		defer t.hello()
		defer t.hello2()
	}
}

输出结果为:

pointer: C
Hello, C
pointer: C
Hello, B
pointer: C
Hello, A

我的理解是,在 3 次循环后,指针 t 将指向 "C",因此会有三个 "C" 的输出。然而,延迟调用的 "hello" 函数的行为非常奇怪。它似乎保留了它所指向的位置。(t Test) 对此有什么影响呢?

我非常好奇 Golang 将其编译成什么样子。非常感谢!

英文:

I wrote the following golang code and ran it.

type Test struct {
	Name string
}

func (t Test) hello() {
	fmt.Printf("Hello, %s\n", t.Name)
}

func (t *Test) hello2() {
	fmt.Printf("pointer: %s\n", t.Name)
}

func runT(t Test) {
	t.hello()
}

func main() {
	mapt := []Test{
		{Name: "A"},
		{Name: "B"},
		{Name: "C"},
	}

	for _, t := range mapt {
		defer t.hello()
		defer t.hello2()
	}
}

The output:

pointer: C
Hello, C
pointer: C
Hello, B
pointer: C
Hello, A

What I understood is that the pointer t will be pointed to "C" after 3 loops thus three 3 "C"s for "hello2" output. However, the behavior of deferred "hello" function call is very curious. It looked like it was preserving where it was pointing to. How does (t Test) affect this?

I'm very curious about what Golang compiles this into. Thank you so much!

答案1

得分: 3

在for循环内部,defer语句的参数是一个闭包。闭包捕获了循环变量t

对于使用值接收器的调用,闭包包含了t的一个副本。对于使用指针接收器的调用,闭包包含了指向t的指针。

循环变量在每次迭代时都会被重写(这种行为将在语言的后续版本中更改)。因此,值接收器的闭包捕获了每个值,而指针接收器的闭包只捕获了指针,因此在运行时它们使用的是该指针的最新值。

英文:

Inside the for-loop, the argument to the defer statement is a closure. The closure captures the loop variable t.

For the call that uses the value receiver, the closure includes a copy of t. For the call that uses the pointer receiver, the closure includes a pointer to t.

Loop variables are rewritten at every iteration (this behavior will be changed in a later version of the language). Because of this, the value receiver closures capture every value, wheres the pointer receiver closures only capture the pointer, thus, when run, they work with the latest value of that pointer.

huangapple
  • 本文由 发表于 2023年4月2日 02:53:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/75908231.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定