Go语言嵌入foos切片的bar结构体初始化:foo.b赋值失效问题
Go中结构体切片循环赋值不生效的问题解决
这是个很典型的Go切片遍历误区,我来帮你拆解问题并给出解决方案:
问题根源
你在newBar()的循环里修改foo.b = true没生效,核心原因是:用range遍历切片时,循环变量是原切片元素的副本,而非指向原元素的引用。你修改的只是这个临时副本的字段值,原切片里的元素完全没被改动。而直接通过索引b.foos[0].b = true操作的是原切片中的实际元素,所以能成功修改。
解决方案
这里有两种简单有效的解决方式:
方案1:通过索引遍历操作原元素
不需要修改结构体定义,直接改用索引遍历切片,直接操作原切片里的元素:
func newBar() *bar { b := &bar{ foos: make([]foo, 3, 3), } // 用索引遍历,直接访问原切片的元素 for i := range b.foos { b.foos[i].b = true } return b }
方案2:改用指针类型的切片
如果你的业务场景需要频繁修改切片元素,或者元素本身比较大,可以将foos定义为指针切片,这样range遍历拿到的就是指向原元素的指针,修改指针指向的字段会直接生效:
package main import ( "fmt" ) type foo struct { a int b bool } type foos []*foo // 修改为指针类型切片 type bar struct { foos } func newBar() *bar { b := &bar{ foos: make([]*foo, 3, 3), } for i := range b.foos { // 先初始化每个foo指针实例 b.foos[i] = &foo{} b.foos[i].b = true } return b } func main() { b := newBar() fmt.Println(b) b.foos[0].b = true // 依然可以正常修改 fmt.Println(b) }
验证效果
修改后运行main函数,两种方案都能让newBar()初始化出的bar中所有foo的b字段为true,完全符合你的预期。
内容的提问来源于stack exchange,提问作者billyzaelani
相关产品推荐
相关产品推荐

