douxin8749 2014-12-22 20:36
浏览 16
已采纳

Golang,仅附加最后一个元素

Here is example code:

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
", pview.Attr, prod) // output for debug
            prod.AttrVals = append(prod.AttrVals, pview.Attr)
        }
    }
    fmt.Printf("%+v
", prod) // output for debug

}

http://play.golang.org/p/949w5tYjcH

Here i have some returned data from DB in ProductAttrValView struct and want put it into Product struct and also fill Product.AttrVals

It prints:

&{Id:1 Title:test AttrVals:[text4]}

While i expect this:

&{Id:1 Title:test AttrVals:[text1 text2 text3 text4]}

So, all text should be appended, but for some reason only the last element stays in Attrs slice.

  • 写回答

1条回答 默认 最新

  • dongquepao8653 2014-12-22 20:42
    关注

    You are re-using variables in your for-range loop, and each iteration modifies the value of that same variable. You can create a new value each iteration with the trick:

    pview := pview
    

    http://play.golang.org/p/qtJXxdtuq2

    You also initialize the slice with a length of 4, but you append another value (ignoring the first 4). You likely meant to set the capacity of the slice as opposed to the length:

    prod.AttrVals = make([]string, 0, len(prodViews))
    

    Because the value of prod is changing each iteration, the code would be a lot less confusing if you specifically initialized the prod value, instead of assigning the address of &pview.Product

    prod = &Product{AttrVals: make([]string, 0, len(prodViews))}
    

    [time line]

    1. You create a single product p, containing an initialized []string
    2. That same p is assigned to all prodViews that we will iterate over.
    3. On the first iteration through the loop, you assign *prod to that initial p value, then change AttrVals to a new []string of length 4. This doesn't alter the original p.
    4. pview.Attr is appended to prod.AttrVals, making a it length 5, and creating a new underlying array. This isn't reflected in the values of p.
    5. On subsequent iterations, pview is overwritten with the next value in prodViews. This overwrites the value of prod too, since it points to the pview.Product value. This means that prod.AttrVals is now the same one from the original p.
    6. pview.Attr is appended to a slice of length 0, and the underlying array is replaced with more capacity, so pview.Attr still isn't contained in the original p.
    7. pview is again overwritten with the next value, which contains original p values, setting your AttrVals length back to 0 with an empty array.
    8. The cycle continues until the final single value is printed.
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 不同尺寸货物如何寻找合适的包装箱型谱
  • ¥15 求解 yolo算法问题
  • ¥15 虚拟机打包apk出现错误
  • ¥30 最小化遗憾贪心算法上界
  • ¥15 用visual studi code完成html页面
  • ¥15 聚类分析或者python进行数据分析
  • ¥15 三菱伺服电机按启动按钮有使能但不动作
  • ¥15 js,页面2返回页面1时定位进入的设备
  • ¥50 导入文件到网吧的电脑并且在重启之后不会被恢复
  • ¥15 (希望可以解决问题)ma和mb文件无法正常打开,打开后是空白,但是有正常内存占用,但可以在打开Maya应用程序后打开场景ma和mb格式。