关于json 的 unmarshal 受主为map[string]interface{} 类型断言的机制问题

str := []byte(`{"id":100006}`)
var a map[string]interface{}
err := json.Unmarshal(str, &a)
if err != nil {
    fmt.Println(err)
    return
}
fmt.Println(a["id"])

结果是 100006

然后值再多一位

str := []byte(`{"id":1000006}`)
var a map[string]interface{}
err := json.Unmarshal(str, &a)
if err != nil {
    fmt.Println(err)
    return
}
fmt.Println(a["id"])

结果就变成了1.000006e+06

是因为位数长了 自动把类型断言改变了吗?
怎样可以正常显示1000006?

共 9 个回复


yxllin

只要位数一长 显示就会变成了科学计数法,怎么样才能让他不用这种方式显示呢

# 0

stevewang

你定义一个struct去解析不就好了吗?

type T struct {
    Id int `json::"id"`
}
# 1

yxllin

@stevewang
因为 有时候解析的json 内容是不确定的,所以没法直接定义一个struct。因而选择了用map

# 2

stevewang

那你可以拿到原始数据自己解析。

    str := []byte(`{"id":1000006}`)
    var a map[string]json.RawMessage
    err := json.Unmarshal(str, &a)
    if err != nil {
        fmt.Println(err)
        return
    }
    var id int
    json.Unmarshal(a["id"], &id)
    fmt.Println(id)
# 3

yxllin

不对呀,,楼上的代码 还是得提前知道字段的属性才能输出,,,不知道的时候没法正常输出。。。
switch a[“id”].(type){
case int:
case float64:
case string:

}
这样判断一下才行。

# 5

stevewang

a[“id”]的类型是RawMessage,实际上是[]byte。怎么解析这个数据,控制权在你的手里。

对于{"id":1000006},a[“id”]的值就是[]byte("1000006")。你可以把这个值解析为int或者float。

对于{"id":"1000006"},a[“id”]的值就是[]byte("\"1000006\"")。(注意前后多了两个引号)

# 6

howcrazy

这是由于JSON里的数字默认都会转成golang的float64类型引起的

进行json解析时,若以interface{}接收数据,则会按照下列规则进行解析:

bool, for JSON booleans
float64, for JSON numbers
string, for JSON strings
[]interface{}, for JSON arrays
map[string]interface{}, for JSON objects
nil for JSON null

而浮点数打印时的默认规则是超过一定长度后会换成科学计数法打印。

因此,只要在打印时指定打印格式,或者(按照LZ示例里是整数的情况时),转换为整数打印

fmt.Println(int(a["id"].(float64)))
# 7

lstarboy

使用JsonNumber即可
reader := bytes.NewReader(str)
dec := json.NewDecoder(reader)
dec.UseNumber()
err = dec.Decode(&val)
# 8