英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论