2015-09-04 26 views
0

我在Go中使用for range循环遍历一个结构片段。执行循环指针更改

在每个循环中,我将一个指向当前项的指针指向一个变量。

我很困惑,为什么指针在下一个循环中改变了值。

例如this code

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} 

供参考,在我实际的代码,我检查对于循环中的条件,并返回当前项目和前一个项目。所以我试图保存一个指向它的指针,这样在下一次迭代中它也可以访问前一个指针。

+4

在每次循环迭代开始时,'for'将'l'的当前元素**复制到'i'中。 –

+0

因此,它基本上重复使用一个'i'来进行所有迭代? 我认为这是有道理的。如果我在循环中,那么我将如何保存一个指向实际对象的指针? –

回答

1

的问题是,你正在服用环/范围变量的地址,而不是地址切片中的项目。但是,你只是为自己做了很多不必要的工作。首先,您为什么不使用i, v := range或更好的i, _ :=,然后您可以使用i-1来获取上一个项目?其次,即使你想把它保存在一个指针中,仍然使用这个语法,然后分配p = &l[i],这样你就得到了片中的项目地址,而不是循环/范围变量的地址。

人们太渴望用于/每种风格的构造,当它明显更好地使用索引时...如果你想在每次迭代时使用索引-1,那么使用索引应该是你去做的方式。

1

建立关闭Tim's comment,似乎你可以复制每个循环的值,而不是指针,并将其解引用。

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) 
    } 
} 
+1

在这里查看FAQ条目:http://golang.org/doc/faq#closures_and_goroutines。当你不使用闭包时,'i:= i'成语可能是最常见的解决方案。 – JimB

+0

@JimB谢谢,这非常相关。 –

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) 
    } 
}