我有一个数据结构:
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处没有元素,并且没有任何要分配的元素。
修复
两种方式:
预分配目标片段:
var dataGrouped DataGroupedByTS // ... dataGrouped.Details = make([]struct{...}, len(apiMain.Details)) for _, detail := range apiMain.Details { // ...
附加到切片,而不是修补其元素:
var dataGrouped DataGroupedByTS // ... for _, detail := range apiMain.Details { dataGrouped.Details = append(dataGrouped.Details, detail) // ...
append
到nil
切片是可以的。