Go循环指针变化

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

Go loop pointer changes

问题

我正在使用Go语言中的for range循环来遍历一个结构体切片。

在每次循环中,我将当前项的指针赋值给一个变量。

我对于为什么指针在下一次循环中会改变值感到困惑。

例如,这段代码

package main

import "fmt"

type t struct {
    val int
}

func main() {
    l := []t{{1}, {2}}
    var p *t
    for _, i := range l {
        fmt.Println("begin", p)
        p = &i
        fmt.Println("end", p)
    }
}

我期望的输出是:

begin <nil>
end &{1}
begin &{1}
end &{2}

但实际输出是:

begin <nil>
end &{1}
begin &{2}
end &{2}

作为参考,我在实际代码中,在循环期间检查一个条件,并返回当前项和前一项。所以我试图保存一个指向它的指针,以便在下一次迭代中也能访问到前一项。

英文:

I am using a for range loop in Go to iterate through a slice of structs.

In each loop, I a pointer to the current item to a variable.

I am confused why the pointer changes value in the next loop.

For example this code:

package main

import &quot;fmt&quot;

type t struct {
	val int
}

func main() {
	l := []t{{1}, {2}}
	var p *t
	for _, i := range l {
		fmt.Println(&quot;begin&quot;, p)
		p = &amp;i
		fmt.Println(&quot;end&quot;, p)
	}
}

I would expect to produce:

begin &lt;nil&gt;
end &amp;{1}
begin &amp;{1}
end &amp;{2}

But actually does:

begin &lt;nil&gt;
end &amp;{1}
begin &amp;{2}
end &amp;{2}

For reference, in my actual code, I am checking for a condition during the loop, and returning the current item and previous one. So I am trying to save a pointer to it, so that in the next iteration it will have access to the previous as well.

答案1

得分: 1

根据Tim的评论,似乎你可以在每次循环中复制值,而不是指针,并在之后解引用它。

package main

import "fmt"

type t struct {
    val int
}

func main() {
    l := []t{{1}, {2}}
    var p t
    var i t
    for _, i = range l {
        fmt.Println("begin", &p)
        p = i
        fmt.Println("end", &p)
    }
}
英文:

Building off Tim's comment, it seems like you can copy the value on each loop, instead of the pointer, and dereference it after.

package main

import &quot;fmt&quot;

type t struct {
	val int
}

func main() {
	l := []t{{1}, {2}}
	var p t
	var i t
	for _, i = range l {
		fmt.Println(&quot;begin&quot;, &amp;p)
		p = i
		fmt.Println(&quot;end&quot;, &amp;p)
	}
}

答案2

得分: 1

另一种选择是通过使用索引来获取当前项的指针:

package main

import "fmt"

type t struct {
    val int
}

func main() {
    l := []t{{1}, {2}}
    var p *t
    
    for index, _ := range l {
        fmt.Println("begin", p)
        p = &l[index]
        fmt.Println("end", p)
    }
}

另外一个选项是通过使用索引来获取当前项的指针:

package main

import "fmt"

type t struct {
    val int
}

func main() {
    l := []t{{1}, {2}}
    var p *t
    
    for index, _ := range l {
        fmt.Println("begin", p)
        p = &l[index]
        fmt.Println("end", p)
    }
}
英文:

Another option is to get the pointer to the current item by using the index:

package main

import &quot;fmt&quot;

type t struct {
	val int
}

func main() {
	l := []t{{1}, {2}}
	var p *t
	
	for index, _ := range l {
		fmt.Println(&quot;begin&quot;, p)
		p = &amp;l[index]
		fmt.Println(&quot;end&quot;, p)
	}
}

答案3

得分: 1

问题在于你取的是循环/范围变量的地址,而不是切片中项的地址。然而,你只是给自己增加了很多不必要的工作。首先,为什么不使用i, v := range或者更好的是i, _ :=,然后你可以使用i-1来获取前一个项?其次,即使你想将其保存在指针中,仍然使用这种语法,然后赋值p = &l[i],这样你就有了切片中项的地址,而不是循环/范围变量的地址。

人们在明显更好使用索引的情况下过于急于使用for/each风格的结构...如果你想在每次迭代中使用索引-1,使用索引应该是你首选的方法。

英文:

The problem is that you're taking the address of the loop/range variable and not the address of the item in slice. However, you're just making a lot of unnecessary work for yourself. For one, why don't you use the i, v := range or better yet i, _ := and then you can do i-1 to get the previous item? Secondly, even if you want it saved in a pointer, still use this syntax and then assign p = &amp;l[i] so you have the address of the item in the slice rather than the address of the loop/range variable.

People are way too eager to use for/each style constructs when it's obviously better to work with the index... If you want index-1 on every iteration, using the index should be your go to way of doing that.

huangapple
  • 本文由 发表于 2015年9月4日 23:44:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/32401933.html
匿名

发表评论

匿名网友

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

确定