This for range
loop:
for _, each := range numbers {
迭代的元素numbers
切片,并在每次迭代中分配 (copies) 的一个元素each
循环变量。
自从你的numbers
切片的类型是[]Number
,它将复制Number
构造成each
变量(其类型为Number
).
然后你调用Number.Increment()
方法对此变量。自从Increment()
有指针接收器,这是一个简写(&each).Increment()
。因此,该循环变量的地址被用作Increment()
方法。这Increment()
方法将正确更改此循环变量,但这是独立的、不同的、与切片分离的,因此您不会修改切片中的元素。
当你这样做时:
for i := 0; i < len(numbers); i++ {
numbers[i].Increment()
}
要点numbers
这里就不复制了。这:
numbers[i].Increment()
索引numbers
切片,并且由于Increment()
有一个指针接收器,地址为numbers[i]
被取出并使用,即元素的地址在切片中。所以在这里,您将修改Number
切片的结构体值。
请注意,您还可以使用for range
here:
for i := range numbers {
numbers[i].Increment()
}
在切片上进行范围变化时的第一个迭代变量是索引。
另外,如果您将指针存储在numbers
切片(然后其类型为[]*Number
),同样的事情也会发生,但在这种情况下for range
将复制指针,而不是结构,并且循环变量中的指针将指向相同的Number
结构值就像切片中的指针一样,因此这也适用于您的第一个for range
变体。
所有这些都详细说明在规格:用于报表 https://golang.org/ref/spec#For_statements, 在里面对于带有范围子句的语句小节。