英文:
How to Unmarshal list of varied types without defaulting to float64
问题
我有以下的JSON数据(来自外部程序,稍作简化)我无法更改JSON格式。
[1416495600501595942, {"venue_id": 73, "message_type": "ABC", "sequence": 26686695}]
我在Go语言中解析它时遇到了问题,我认为主要是因为它是一个不同类型的列表。显而易见的做法似乎是使用[]interface{}
,这样可以工作,但它会将其转换为float64
,这会产生一个我无法处理的舍入误差(该数字是自纪元以来的纳秒时间戳)。
我可以通过两次解析来使其工作,即[]interface{}
和[]int64
,但这显然会影响性能,而且我正在实时处理大量数据。
我尝试使用结构体,因为它会被视为映射而不是列表[]
。
是否有任何方法可以传递数据的格式,或者使其默认为int64
而不是float64
?它的格式总是这样的:
[int64, map[string]interface{}]
也就是说,我知道上层列表的格式,以及映射的键是字符串,但值可以是任何类型(包括小数,我认为我只能将它们解释为浮点数...)
以下是我的代码:
package main
import (
"encoding/json"
"fmt"
)
func main() {
j := `[1416495600501595942, {"venue_id": 73, "message_type": "ABC", "sequence": 26686695}]`
b := []byte(j)
fmt.Println(j)
var line []interface{}
var ints []int64
json.Unmarshal(b, &line)
fmt.Println(line)
// fmt.Println(line[0].(int64)) - this doesn't work
fmt.Println(line[0].(float64))
fmt.Println(int64(line[0].(float64)))
json.Unmarshal(b, &ints)
fmt.Println(ints)
}
输出如下:
[1416495600501595942, {"venue_id": 73, "message_type": "ABC", "sequence": 26686695}]
[1.416495600501596e+18 map[venue_id:73 message_type:ABC sequence:2.6686695e+07]]
1.416495600501596e+18
1416495600501595904
[1416495600501595942 0]
解决方案(感谢makpoc / dystroy):
package main
import (
"encoding/json"
"fmt"
"bytes"
)
func main() {
j := `[1416495600501595942, {"venue_id": 7.3, "message_type": "ABC", "sequence": 26686695}]`
b := []byte(j)
fmt.Println(j)
var line []interface{}
d := json.NewDecoder(bytes.NewBuffer(b))
d.UseNumber()
if err := d.Decode(&line); err != nil {
panic(err)
}
fmt.Println(line[0])
data := line[1].(map[string]interface{})
fmt.Println(data["venue_id"])
fmt.Println(data["sequence"])
}
希望对你有帮助!
英文:
I have the following json data (from an external program, simplified a bit)
I can't change the json format.
[1416495600501595942, {"venue_id": 73, "message_type": "ABC", "sequence": 26686695}]
I'm having trouble unpacking it in Go, I think mostly because it's a list of disparate types.
The obvious thing to do seems to be to do is []interface{}, which works, but in converts it to a float64, which produces a roundoff error that I can't deal with (the number is a timestamp since epoch in nanos).
I can get it to work by unpacking it twice, as []interface{} and []int64, but that's obviously going to hinder performance, and I'm processing large amounts of data in real time.
I tried using struct here because that would get treated as a map, not a list[]
Is there any way to either pass it the format of the data, or make it default to int64 instead of float64? It's always going to be
[int64, map[string]interface{}]
ie I know the format of the upper level list, and that the keys of the map are strings, but the values could be anything (painfully, including decimals, which I think the only thing I can use to interpret them as is floats ...)
package main
import (
"encoding/json"
"fmt"
)
func main() {
j := `[1416495600501595942, {"venue_id": 73, "message_type": "ABC", "sequence": 26686695}]`
b := []byte(j)
fmt.Println(j)
var line []interface{}
var ints []int64
json.Unmarshal(b, &line)
fmt.Println(line)
// fmt.Println(line[0].(int64)) - this doesn't work
fmt.Println(line[0].(float64))
fmt.Println(int64(line[0].(float64)))
json.Unmarshal(b, &ints)
fmt.Println(ints)
}
Output is as follows:
<pre>
[1416495600501595942, {"venue_id": 73, "message_type": "oKC", "sequence": 26686695}]
[1.416495600501596e+18 map[venue_id:73 message_type:oKC sequence:2.6686695e+07]]
1.416495600501596e+18
1416495600501595904
[1416495600501595942 0]
</pre>
Solution (thanks to makpoc / dystroy)
package main
import (
"encoding/json"
"fmt"
"bytes"
)
func main() {
j := `[1416495600501595942, {"venue_id": 7.3, "message_type": "oKC", "sequence": 26686695}]`
b := []byte(j)
fmt.Println(j)
var line []interface{}
d := json.NewDecoder(bytes.NewBuffer(b))
d.UseNumber()
if err := d.Decode(&line); err != nil {
panic(err)
}
fmt.Println(line[0])
data := line[1].(map[string]interface{})
fmt.Println(data["venue_id"])
fmt.Println(data["sequence"])
}
答案1
得分: 1
根据这个答案,你可以使用Decoder -> 和UseNumber或者一个结构体来代替直接解析值。
英文:
According to this answer you can use Decoder -> and UseNumber or a struct instead of directly parsing the value.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论