以下是示例代码:
package main
import (
"fmt"
)
type Product struct {
Id int64
Title string
AttrVals []string
}
type ProductAttrValView struct {
Product
Attr string
}
type ProductAttrVal struct {
Attr string
Product int64
Value string
}
func main() {
p := Product{Id: 1, Title: "test", AttrVals: []string{}}
var prod *Product
prodViews := []ProductAttrValView{
ProductAttrValView{ Product: p, Attr: "text1" },
ProductAttrValView{ Product: p, Attr: "text2" },
ProductAttrValView{ Product: p, Attr: "text3" },
ProductAttrValView{ Product: p, Attr: "text4" },
}
// collapse join View to Product with Attrs
for _, pview := range prodViews {
if prod == nil {
prod = &pview.Product
prod.AttrVals = make([]string, 0, len(prodViews))
}
if pview.Attr != "" {
fmt.Printf("appending '%s' to %p\n", pview.Attr, prod) // output for debug
prod.AttrVals = append(prod.AttrVals, pview.Attr)
}
}
fmt.Printf("%+v\n", prod) // output for debug
}
http://play.golang.org/p/949w5tYjcH
这里我有一些来自ProductAttrValView
struct中的DB的返回数据
将其放入Product
结构中,并填写Product.AttrVals
打印:
& {Id:1 Title:test AttrVals:[text4]}
虽然我期待这一点:
& {Id:1 Title:test AttrVals:[text1 text2 text3 text4]}
因此,应附加所有文本,但由于某种原因,只有最后一个元素保留在Attrs
切片中。
答案 0 :(得分:1)
您正在重新使用for-range循环中的变量,并且每次迭代都会修改该变量的值。您可以使用技巧每次迭代创建一个新值:
pview := pview
http://play.golang.org/p/qtJXxdtuq2
您也可以初始化长度为4的切片,但是append
另一个值(忽略前4个)。您可能需要设置切片的容量而不是长度:
prod.AttrVals = make([]string, 0, len(prodViews))
因为prod
的值正在改变每次迭代,所以如果你专门初始化prod
值而不是分配地址,那么代码会更加混乱。 &pview.Product
prod = &Product{AttrVals: make([]string, 0, len(prodViews))}
p
,其中包含一个初始化的[]字符串p
已分配给我们将迭代的所有prodViews
。*prod
分配给该初始p
值,然后将AttrVals
更改为长度为4的新[]string
。这不会&# 39;改变原来的p
。pview.Attr
附加到prod.AttrVals
,使其长度为5,并创建一个新的底层数组。这并未反映在p
。pview
会被prodViews
中的下一个值覆盖。这也会覆盖prod
的值,因为它指向pview.Product
值。这意味着prod.AttrVals
现在与原始p
中的pview.Attr
相同。pview.Attr
附加到长度为0的切片,并且底层数组将替换为更多容量,因此p
仍未包含在原始pview
中。< / LI>
p
再次被下一个值覆盖,该值包含原始AttrVals
值,使用空数组将{{1}}长度设置回0。