5
初学 golang,小白求解惑!
source link: https://www.v2ex.com/t/817965
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
package main
import "fmt"
type Test struct {
Id int64
Name string
}
func main() {
var list = []Test{
Test{Id: 1, Name: "1XX"},
Test{Id: 2, Name: "2XX"},
Test{Id: 3, Name: "3XX"},
}
for _, v := range list {
v.Name = "888"
}
fmt.Println(list)
}
为啥修改 Name 貌似没生效
第 1 条附言 · 16 小时 29 分钟前
习惯了写 js ,学习 go 有点不适应啊!!
22 条回复 • 2021-11-26 09:46:55 +08:00
wunonglin 16 小时 49 分钟前 1
```
func main() {
var list = []*Test{
{Id: 1, Name: "1XX"},
{Id: 2, Name: "2XX"},
{Id: 3, Name: "3XX"},
}
for _, v := range list {
v.Name = "888"
}
for _, v := range list {
fmt.Printf("%+v\n", v)
}
}
```
用指针就好了
func main() {
var list = []*Test{
{Id: 1, Name: "1XX"},
{Id: 2, Name: "2XX"},
{Id: 3, Name: "3XX"},
}
for _, v := range list {
v.Name = "888"
}
for _, v := range list {
fmt.Printf("%+v\n", v)
}
}
```
用指针就好了
Rooger 16 小时 43 分钟前 1
原因:for range 的方式其实一种 copy 了 list 。
两种修改方式,一种就是 `list[k].Name = 888`,另一种是将 slice 修改为存储指针 var list = []*Test 。
同样的坑你也应该注意,不能使用 k 和 v 的地址。
两种修改方式,一种就是 `list[k].Name = 888`,另一种是将 slice 修改为存储指针 var list = []*Test 。
同样的坑你也应该注意,不能使用 k 和 v 的地址。
corningsun 13 小时 11 分钟前
@whyso
Java 和 Go 的 for 循环 默认策略完全相反。
Java 必须要主动拷贝才会新建对象。这种 List 结构还得深拷贝,不然用的还是同一个对象。
Go 和 Java stream() 比较像了。
Java 和 Go 的 for 循环 默认策略完全相反。
Java 必须要主动拷贝才会新建对象。这种 List 结构还得深拷贝,不然用的还是同一个对象。
Go 和 Java stream() 比较像了。
yrj 11 小时 13 分钟前 via iPad
你这么理解,range 的时候,其实是 copy 了一份新的数据给 for 所以你在 for 里修改的是 copy 的新数据。可以按照楼上指针的写法,原理是直接操作了指针
mmuggle 10 小时 22 分钟前
虽然 for range 确实是循环的副本,但是这个是循环的切片,切片结构是指向一个底层数组的指针
所以我觉得原因是 v 是在 for 循环的时候初始化的,循环体中修改的是 v 的 Name ,而不是切片元素的 Name
所以我觉得原因是 v 是在 for 循环的时候初始化的,循环体中修改的是 v 的 Name ,而不是切片元素的 Name
SimbaPeng 8 小时 54 分钟前 8
我真的怀疑楼上的回复者,真的会 Golang ?
什么 range copy 了 list ,range 策略,深拷贝浅拷贝?能不能不要在这里误人子弟?
这里的关键就是 v := range list 是个赋值操作,将 list 元素赋值给 v ,golang 里只有值传递,所以 list 元素在复制给 v 的时候必然产生了拷贝。而结构体是值类型,没有引用的对象,所以是拷贝整个结构体,直接修改 v 的属性就是修改拷贝的结构体,所以原结构体属性并不会改变。
同理,但凡你将一个结构体赋值给一个新变量,然后修改新变量的字段,都不会对原结构体有任何影响。
这跟你用没用 range 一点关系都没有。
如果你的 list 里存的是结构体的指针,range 的时候一样会产生拷贝,不过拷贝的是指针结构,底层引用的结构体不会产生拷贝,所以你解指针修改字段的时候,修改的是同一个结构体。但如果将一个新的指针赋值给 v ,原 list 的元素依然不会被改变。
最后总结一句话,golang 只有值传递。
什么 range copy 了 list ,range 策略,深拷贝浅拷贝?能不能不要在这里误人子弟?
这里的关键就是 v := range list 是个赋值操作,将 list 元素赋值给 v ,golang 里只有值传递,所以 list 元素在复制给 v 的时候必然产生了拷贝。而结构体是值类型,没有引用的对象,所以是拷贝整个结构体,直接修改 v 的属性就是修改拷贝的结构体,所以原结构体属性并不会改变。
同理,但凡你将一个结构体赋值给一个新变量,然后修改新变量的字段,都不会对原结构体有任何影响。
这跟你用没用 range 一点关系都没有。
如果你的 list 里存的是结构体的指针,range 的时候一样会产生拷贝,不过拷贝的是指针结构,底层引用的结构体不会产生拷贝,所以你解指针修改字段的时候,修改的是同一个结构体。但如果将一个新的指针赋值给 v ,原 list 的元素依然不会被改变。
最后总结一句话,golang 只有值传递。
SimbaPeng 8 小时 23 分钟前
```
func main() {
a := []int{1, 2, 3}
for i, v := range a {
if i == 0 {
a[2] = 4
}
fmt.Println(v)
}
}
```
那些说是因为 range 的是 list 的副本的,自己运行一下这段代码。copy 的是切片,又不是底层数组。
func main() {
a := []int{1, 2, 3}
for i, v := range a {
if i == 0 {
a[2] = 4
}
fmt.Println(v)
}
}
```
那些说是因为 range 的是 list 的副本的,自己运行一下这段代码。copy 的是切片,又不是底层数组。
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK