Golang,附加只留下最后一个元素

时间:2014-12-22 20:36:07

标签: go

以下是示例代码:

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切片中。

1 个答案:

答案 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))}

[时间线]

  1. 您创建了一个产品p,其中包含一个初始化的[]字符串
  2. 同样的p已分配给我们将迭代的所有prodViews
  3. 在循环的第一次迭代中,您将*prod分配给该初始p值,然后将AttrVals更改为长度为4的新[]string。这不会&# 39;改变原来的p
  4. pview.Attr附加到prod.AttrVals,使其长度为5,并创建一个新的底层数组。这并未反映在p
  5. 的值中
  6. 在后续迭代中,pview会被prodViews中的下一个值覆盖。这也会覆盖prod的值,因为它指向pview.Product值。这意味着prod.AttrVals现在与原始p中的pview.Attr相同。
  7. pview.Attr附加到长度为0的切片,并且底层数组将替换为更多容量,因此p仍未包含在原始pview中。< / LI>
  8. p再次被下一个值覆盖,该值包含原始AttrVals值,使用空数组将{{1}}长度设置回0。
  9. 循环继续,直到打印出最终的单个值。