Go 语言json.Unmarshal 遇到的小问题(推荐)

2022-07-30,,,

1.问题现象描述

使用 json.unmarshal(),反序列化时,出现了科学计数法,参考代码如下:

jsonstr := `{"number":1234567}`
result := make(map[string]interface{})
err := json.unmarshal([]byte(jsonstr), &result)
if err != nil {
	fmt.println(err)
}
fmt.println(result)

// 输出
// map[number:1.234567e+06]

这个问题不是必现,只有当数字的位数大于 6 位时,才会变成了科学计数法。

2.问题影响描述

当数据结构未知,使用 map[string]interface{} 来接收反序列化结果时,如果数字的位数大于 6 位,都会变成科学计数法,用到的地方都会受到影响。

3.引起问题的原因

encoding/json 可以找到答案,看一下这段注释:

// to unmarshal json into an interface value,
// unmarshal stores one of these in the interface value:
//
//	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

是因为当 json 中存在一个比较大的数字时,它会被解析成 float64 类型,就有可能会出现科学计数法的形式。

4.问题的解决方案

方案一

强制类型转换,参考代码如下:

jsonstr := `{"number":1234567}`
result := make(map[string]interface{})
err := json.unmarshal([]byte(jsonstr), &result)
if err != nil {
	fmt.println(err)
}
fmt.println(int(result["number"].(float64)))

// 输出
// 1234567

方案二

尽量避免使用 interface,对 json 字符串结构定义结构体,快捷方法可使用在线工具:https://mholt.github.io/json-to-go/

type num struct {
	number int `json:"number"`
}

jsonstr := `{"number":1234567}`
var result num
err := json.unmarshal([]byte(jsonstr), &result)
if err != nil {
	fmt.println(err)
}
fmt.println(result)

// 输出
// {1234567}

方案三

使用 usenumber() 方法。

jsonstr := `{"number":1234567}`
result := make(map[string]interface{})
d := json.newdecoder(bytes.newreader([]byte(jsonstr)))
d.usenumber()
err := d.decode(&result)
if err != nil {
	fmt.println(err)
}
fmt.println(result)

// 输出
// map[number:1234567]

这时一定要注意 result["number"] 的数据类型!

fmt.println(fmt.sprintf("type: %v", reflect.typeof(result["number"])))

// 输出
// type: json.number

通过代码可以看出 json.number 其实就是字符串类型:

// a number represents a json number literal.
type number string

如果转换其他类型,参考如下代码:

// 转成 int64
numint, _ := result["number"].(json.number).int64()
fmt.println(fmt.sprintf("value: %v, type: %v", numint, reflect.typeof(numint)))

// 输出
// value: 1234567, type: int64

// 转成 string
numstr := result["number"].(json.number).string()
fmt.println(fmt.sprintf("value: %v, type: %v", numstr, reflect.typeof(numstr)))

// 输出
// value: 1234567, type: string

到此这篇关于go 语言json.unmarshal 遇到的小问题(推荐)的文章就介绍到这了,更多相关go 语言json.unmarshal内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!

《Go 语言json.Unmarshal 遇到的小问题(推荐).doc》

下载本文的Word格式文档,以方便收藏与打印。