pointers - 如果对象在切片中,方法不会改变对象的值
问题描述
这是我的程序:
package main
import (
"fmt"
)
type Number struct {
val int
}
func (num * Number) Increment () {
num.val += 1
}
func (num Number) Value() int {
return num.val
}
func main() {
numbers := []Number {
{val: 12},
{val: 7},
{val: 0},
}
for _, each := range numbers {
each.Increment()
fmt.Println(each.Value())
}
for _, each := range numbers {
fmt.Println(each.Value())
}
}
这是输出:
13
8
1
12
7
0
第一个问题:为什么Increment()
方法不更新第一个for循环中的值?我使用指针作为接收器,因此val
可以肯定地对其进行更新,但是为什么第二个for
循环会打印出那些Number
s 的原始值呢?
第二个问题:可以做些什么,以便当我遍历一个Number
s 切片并调用该Increment()
方法时,所有Number
s 都正确递增?
[编辑]我注意到如果我使用基于索引的for
循环并调用该Increment()
方法,值将被正确更新。为什么?
for i := 0; i < len(numbers); i++ {
numbers[i].Increment()
}
解决方案
这个for range
循环:
for _, each := range numbers {
迭代numbers
切片的元素,并在每次迭代中将一个元素分配(复制each
)给循环变量。
由于您的numbers
切片是 type []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
对slice 进行索引,由于Increment()
有指针接收器,所以取并使用 的地址,即 slicenumbers[i]
中元素的地址。所以在这里,您将修改切片的结构值。Number
请注意,您也可以for range
在此处使用:
for i := range numbers {
numbers[i].Increment()
}
遍历切片时的第一个迭代变量是索引。
此外,如果您将指针存储在切片中numbers
(然后其类型为值作为切片中的指针,因此这也适用于您的第一个变体。[]*Number
for range
Number
for range
所有这些都在Spec: For statements中详细说明,在For statements with range 子句小节中。
推荐阅读
- google-sheets - 具有有限最大输出的 COUNTIF 公式
- mysql - MYSQL - 错误 1048 (23000): 列不能为空
- unity3d - Facebook SDK for unity - 如何以编程方式设置 App Id?
- python - 在 Python 中仅使用一次数字进行整数分区的递归很慢
- linux - 删除 BeagleBone ai 上先前生成的 .dtb 文件
- python - 保留一个索引,以记录 if 语句在列表理解中传递了多少次
- mysql - 为基于 DOCKER 的应用程序创建 SSH 隧道以连接到数据库?
- excel - 如何在excel中转换自定义日期格式?
- excel - 选择后设置打印区域以适应
- java - 在 Java 中,新建或增强类加载器的用例是什么?