我有一个数据结构:

type APIMain struct {
    CodeConv string    `json:"codeConv"`
    Start    time.Time `json:"start"`
    End      time.Time `json:"end"`
    Details  []struct {
        IDPrm string `json:"idPrm"`
        Keys  []struct {
            Timestamp time.Time `json:"timestamp"`
            Value     float64   `json:"value"`
        } `json:"keys"`
    } `json:"details"`
}

我需要转换为:

type DataGroupedByTS struct {
    CodeConv string    `json:"codeConv"`
    Start    time.Time `json:"start"`
    End      time.Time `json:"end"`
    Details  []struct {
        Timestamp time.Time `json:"timestamp"`
        Keys      []struct {
            IDPrm string  `json:"idPrm"`
            Value float64 `json:"value"`
        } `json:"keys"`
    } `json:"details"`
}

我明白了:

 panic: runtime error: index out of range

这是我的方法,但它在第一行循环失败:

func groupByTimestamp(apiMain datacheck.APIMain) DataGroupedByTS {
    var dataGrouped DataGroupedByTS
    dataGrouped.CodeConv = apiMain.CodeConv
    dataGrouped.Start = apiMain.Start
    dataGrouped.Start = apiMain.Start
    dataGrouped.End = apiMain.End

    var iDetail = 0
    var iKey = 0
    for _, detail := range apiMain.Details {
        for _, key := range detail.Keys {
            dataGrouped.Details[iDetail].Timestamp = key.Timestamp  // <-- failing here
            dataGrouped.Details[iDetail].Keys[iKey].IDPrm = detail.IDPrm
            dataGrouped.Details[iDetail].Keys[iKey].Value = key.Value
            iKey++
        }
        iDetail++
    }

    return dataGrouped
}

基本上,数据最初是由IDPrm分组的,我需要按时间戳对它进行分组。

我该怎么办?是否有任何助手可以帮忙做到这一点?

分析解答

问题

原因很简单:

var dataGrouped DataGroupedByTS

dataGrouped的字段初始化为so-called DataGroupedByTS类型的零值。

任何化合物类型T的零值由 zero-values用于与T的每个字段对应的类型。

因此对于

type DataGroupedByTS struct {
    CodeConv string    `json:"codeConv"`
    Start    time.Time `json:"start"`
    End      time.Time `json:"end"`
    Details  []struct {
        Timestamp time.Time `json:"timestamp"`
        Keys      []struct {
            IDPrm string  `json:"idPrm"`
            Value float64 `json:"value"`
        } `json:"keys"`
    } `json:"details"`
}

零值将是

type DataGroupedByTS struct {
    CodeConv: "",
    Start:    time.Time(0),
    End:      time.Time(0),
    Details:  nil,           // watch this!
}

那是因为Details的类型是[]struct{ ... }, 也就是说,一些结构的切片,任何切片的zero-value都是nil

然后继续尝试在某个索引处写入non-existing切片(好吧,切片没有分配任何支持数组来保存其数据)。 这与"panic: runtime error: index out of range"合理地失败:未分配的切片具有零元素,因此索引0处没有元素,并且没有任何要分配的元素。

修复

两种方式:

  1. 预分配目标片段:

        var dataGrouped DataGroupedByTS
        // ...
        dataGrouped.Details = make([]struct{...}, len(apiMain.Details))
        for _, detail := range apiMain.Details {
        // ...
    
  2. 附加到切片,而不是修补其元素:

        var dataGrouped DataGroupedByTS
        // ...
        for _, detail := range apiMain.Details {
            dataGrouped.Details = append(dataGrouped.Details, detail)
            // ...
    

    appendnil切片是可以的。