英文:
Golang Slice Indexing Value Or Reference?
问题
我正在学习Go语言,并对通过索引切片获取的"thing"感到困惑。
假设我们有一个类型为bag
的结构体:
type bag struct {
item string
}
然后,考虑我们有一个bag
的列表:
itemBag := []bag{
{item: "item1"},
{item: "item2"},
{item: "item3"},
}
现在,我尝试更改itemBag
变量的第一个元素的内容。天真地,我做了以下操作:
item1 := itemBag[0]
item1.item = "not item1"
fmt.Printf("itemBag[0].item == 'not item1'? %v", itemBag[0].item == "not item1")
// 控制台打印 false
我得到的答案是false,因为(如果我理解正确,请纠正我)当我们执行item1 := itemBag[0]
时,我们正在复制itemBag[0]
的值并将其赋给item1
。我相信这就是这篇博客所说的意思。
为了证明这一点,我尝试获取itemBag[0]
的指针并修改其值,结果,我实现了我想要做的事情:
item1 := &itemBag[0]
item1.item = "not item1"
fmt.Printf("itemBag[0].item == 'not item1'? %v", itemBag[0].item == "not item1")
// 控制台打印 true
如果我们说在切片索引(即slice[index])时,我们将获得其值的副本而不是底层项,这是非常有道理的。
现在,当我尝试以下操作时:
itemBag[0].item = "not item1"
fmt.Printf("itemBag[0].item == 'not item1'? %v", itemBag[0].item == "not item1")
结果是true
,这不是我预期的。因为它看起来好像itemBag[0].item
在语法上与先将itemBag[0]
赋给一个变量,然后引用其底层项是一样的。
我觉得我在Go语言课程中漏掉了一个基础章节,请问是否有任何指导/解释?非常感谢!
我尝试过搜索诸如"slice indexing pass by reference"之类的内容,但无法找到准确的关键词进行搜索。
英文:
I am learning go and is confused by the "thing" we get out of indexing a slice.
Consider that we have a struct of type bag
:
type bag struct {
item string
}
Then, consider that we have a list of bags:
itemBag := []bag{
{item: "item1"},
{item: "item2"},
{item: "item3"}
}
Now, I try to change the content of the first element of our itemBag
variable. Naively, I do the following:
item1 := itemBag[0]
item1.item = "not item1"
fmt.Printf("itemBag[0].item == 'not item1'? %v", itemBag[0].item == "not item1")
// console print false
I got the answer as false, because (I think, do correct me if I am wrong) when we do item1 := itemBag[0]
, we are making a copy of the value of itemBag[0]
and assign it to item1
. Which I believe is what is meant by this blog here.
To prove that, I try to obtain the pointer of the itemBag[0]
instead and modify its value, and voila, I achieve what I wanted to do:
item1 := &itemBag[0]
item1.item = "not item1"
fmt.Printf("itemBag[0].item == 'not item1'? %v", itemBag[0].item == "not item1")
// console print true
Which makes a lot of sense if we say that when we do slice indexing (i.e. slice[index]) we'll get copy of its value instead of the underlying item.
Now, when I do the following instead:
itemBag[0].item = "not item1"
fmt.Printf("itemBag[0].item == 'not item1'? %v", itemBag[0].item == "not item1")
The result is true
, which is not what I expected. Because it looks like itemBag[0].item
is syntatically the same as if I first assign itemBag[0]
to a variable and subsequently referring to its underlying item.
I feel like I am missing a basic chapter in the golang course, please, any redirection/explanation will be highly appreciated!
Tried googling things like "slice indexing pass by reference" but couldn't pinpoint the exact keywords to google.
答案1
得分: 5
赋值操作会复制数值。所以当你执行:
item1 = itemBag[0]
你创建了一个 bag
类型对象 itemBag[0]
的副本。现在 item1
拥有了这个副本,对它所做的任何修改都会在副本上进行。
itemptr = &itemBag[0]
赋值操作的右侧是一个指针,所以这个操作会创建指针的副本并将其赋值给 itemptr
。当你执行 itemptr.item="x"
时,它等同于 (*itemptr).item=x
,所以指针的内容被修改了。
itemBag[0]
是一个可寻址的值,也就是说你可以取得它的地址。
https://go.dev/ref/spec#Address_operators
表达式 itemBag[0].item
也是一个可寻址的值,所以你可以给它赋值,这个赋值会反映在切片本身上。
然而,下面的代码不是一个可寻址的值:
m := map[int]bag{1: bag{item: "str"}}
m[1].item = "str1"
这是因为 m[1]
返回的是映射中一个值的副本,对它进行赋值会丢失。然而,下面的代码是可寻址的:
m := map[int]*bag{1: &bag{item: "str"}}
m[1].item = "str1"
这会设置映射中的 bag
的 item
字段。
英文:
Assignment operation copies values. So when you do:
item1 = itemBag[0]
you create a copy of the object at itemBag[0]
, which is of type bag
. Now item1
has a copy of it, and any modifications you make to it will be made on the copy.
itemptr = &itemBag[0]
The right-side of the assignment is a pointer, so this operation creates a copy of that pointer and assigns it to itemptr
. When you do itemptr.item="x"
, it is equivalent to (*itemptr).item=x
, so the contents of the pointer is modified.
itemBag[0]
is an addressable value, i.e. you can take the address of it.
https://go.dev/ref/spec#Address_operators
The expression itemBag[0].item
is also an addressable value, so you can assign something to it, and it will be reflected in the slice itself.
The following, however, is not an addressable value:
m:=map[int]bag{1:bag{item:"str"}}
m[1].item="str1"
This is because m[1]
returns a copy of a value in a map, and assigning a value to it would be lost. The following, however, is addressable:
m:=map[int]*bag{1:&bag{item:"str"}}
m[1].item="str1"
This would set the item
field of the bag
in the map.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论