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 labview程序设计
  • ¥15 为什么在配置Linux系统的时候执行脚本总是出现E: Failed to fetch http:L/cn.archive.ubuntu.com
  • ¥15 Cloudreve保存用户组存储空间大小时报错
  • ¥15 伪标签为什么不能作为弱监督语义分割的结果?
  • ¥15 编一个判断一个区间范围内的数字的个位数的立方和是否等于其本身的程序在输入第1组数据后卡住了(语言-c语言)
  • ¥15 游戏盾如何溯源服务器真实ip?
  • ¥15 Mac版Fiddler Everywhere4.0.1提示强制更新
  • ¥15 android 集成sentry上报时报错。
  • ¥50 win10链接MySQL
  • ¥15 抖音看过的视频,缓存在哪个文件