英文:
preserve int64 values when parsing json in Go
问题
我正在处理一个包含64位整数对象数组的Go中的json POST。当使用json.Unmarshal时,这些值似乎被转换为float64,这并不是很有帮助。
body := []byte(`{"tags":[{"id":4418489049307132905},{"id":4418489049307132906}]}`)
var dat map[string]interface{}
if err := json.Unmarshal(body, &dat); err != nil {
panic(err)
}
tags := dat["tags"].([]interface{})
for i, tag := range tags {
fmt.Println("tag: ", i, " id: ", tag.(map[string]interface{})["id"].(int64))
}
有没有办法在json.Unmarshal的输出中保留原始的int64?
英文:
I'm processing a json POST in Go that contains an array of objects containing 64bit integers. When using json.Unmarshal these values seem to be converted to a float64 which isn't very helpful.
body := []byte(`{"tags":[{"id":4418489049307132905},{"id":4418489049307132906}]}`)
var dat map[string]interface{}
if err := json.Unmarshal(body, &dat); err != nil {
panic(err)
}
tags := dat["tags"].([]interface{})
for i, tag := range tags {
fmt.Println("tag: ", i, " id: ", tag.(map[string]interface{})["id"].(int64))
}
Is there any way to preserve the original int64 in the output of json.Unmarshal?
答案1
得分: 39
解决方案1
您可以使用Decoder和UseNumber来解码您的数字而不会丢失:
Number
类型的定义如下:
// Number表示一个JSON数字字面量。
type Number string
这意味着您可以轻松地进行转换:
package main
import (
"encoding/json"
"fmt"
"bytes"
"strconv"
)
func main() {
body := []byte("{\"tags\":[{\"id\":4418489049307132905},{\"id\":4418489049307132906}]}")
dat := make(map[string]interface{})
d := json.NewDecoder(bytes.NewBuffer(body))
d.UseNumber()
if err := d.Decode(&dat); err != nil {
panic(err)
}
tags := dat["tags"].([]interface{})
n := tags[0].(map[string]interface{})["id"].(json.Number)
i64, _ := strconv.ParseUint(string(n), 10, 64)
fmt.Println(i64) // 输出 4418489049307132905
}
解决方案2
您还可以解码为特定的结构以满足您的需求:
package main
import (
"encoding/json"
"fmt"
)
type A struct {
Tags []map[string]uint64 // "tags"
}
func main() {
body := []byte("{\"tags\":[{\"id\":4418489049307132905},{\"id\":4418489049307132906}]}")
var a A
if err := json.Unmarshal(body, &a); err != nil {
panic(err)
}
fmt.Println(a.Tags[0]["id"]) // 输出 4418489049307132905
}
个人而言,我通常更喜欢这个解决方案,因为它更有结构化和易于维护的感觉。
注意
如果您使用JSON,因为您的应用程序部分使用JavaScript:JavaScript没有64位整数,只有一种数字类型,即IEEE754双精度浮点数。因此,您将无法在JavaScript中使用标准解析函数解析此JSON而不会丢失数据。
英文:
Solution 1
You can use a Decoder and UseNumber to decode your numbers without loss :
The Number
type is defined like this :
// A Number represents a JSON number literal.
type Number string
which means you can easily convert it :
package main
import (
"encoding/json"
"fmt"
"bytes"
"strconv"
)
func main() {
body := []byte("{\"tags\":[{\"id\":4418489049307132905},{\"id\":4418489049307132906}]}")
dat := make(map[string]interface{})
d := json.NewDecoder(bytes.NewBuffer(body))
d.UseNumber()
if err := d.Decode(&dat); err != nil {
panic(err)
}
tags := dat["tags"].([]interface{})
n := tags[0].(map[string]interface{})["id"].(json.Number)
i64, _ := strconv.ParseUint(string(n), 10, 64)
fmt.Println(i64) // prints 4418489049307132905
}
Solution 2
You can also decode into a specific structure tailored to your needs :
package main
import (
"encoding/json"
"fmt"
)
type A struct {
Tags []map[string]uint64 // "tags"
}
func main() {
body := []byte("{\"tags\":[{\"id\":4418489049307132905},{\"id\":4418489049307132906}]}")
var a A
if err := json.Unmarshal(body, &a); err != nil {
panic(err)
}
fmt.Println(a.Tags[0]["id"]) // logs 4418489049307132905
}
Personally I generally prefer this solution which feels more structured and easier to maintain.
Caution
A small note if you use JSON because your application is partly in JavaScript : JavaScript has no 64 bits integers but only one number type, which is the IEEE754 double precision float. So you wouldn't be able to parse this JSON in JavaScript without loss using the standard parsing function.
答案2
得分: 0
body := []byte({"tags":[{"id":4418489049307132905},{"id":4418489049307132906}]}
)
var dat map[string]interface{}
if err := json.Unmarshal(body, &dat); err != nil {
panic(err)
}
tags := dat["tags"].([]interface{})
for i, tag := range tags {
fmt.Printf("tag: %v, id: %.0f", i, tag.(map[string]interface{})["id"].(float64))
}
英文:
easier one:
body := []byte(`{"tags":[{"id":4418489049307132905},{"id":4418489049307132906}]}`)
var dat map[string]interface{}
if err := json.Unmarshal(body, &dat); err != nil {
panic(err)
}
tags := dat["tags"].([]interface{})
for i, tag := range tags {
fmt.Printf("tag: %v, id: %.0f", i, tag.(map[string]interface{})["id"].(float64))
}
答案3
得分: 0
我意识到这是非常旧的,但这是我最终使用的解决方案
/*
跳过之前的代码,这只是将浮点数转换为整数,如果值与小数点后的内容相同
*/
f := tag.(map[string]interface{})["id"].(float64)
if math.Floor(f) == f {
fmt.Println("整数标签: ", i, " id: ", int64(f))
} else {
fmt.Println("标签: ", i, " id: ", f)
}
英文:
I realize this is very old, but this is the solution I ended up using
/*
skipping previous code, this is just converting the float
to an int, if the value is the same with or without what's
after the decimal points
*/
f := tag.(map[string]interface{})["id"].(float64)
if math.Floor(f) == f {
fmt.Println("int tag: ", i, " id: ", int64(f))
} else {
fmt.Println("tag: ", i, " id: ", f)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论