Go - json.Unmarshal 遇到的小坑

简介: Go - json.Unmarshal 遇到的小坑

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)

// 输出
// {123456

方案三

使用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 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


目录
相关文章
|
3月前
|
JSON 人工智能 编译器
Go json 能否解码到一个 interface 类型的值
Go json 能否解码到一个 interface 类型的值
30 1
|
3月前
|
JSON Go 数据格式
Go实现json字符串与各类struct相互转换
文章通过Go语言示例代码详细演示了如何实现JSON字符串与各类struct之间的相互转换,包括结构体对象生成JSON字符串和JSON字符串映射到struct对象的过程。
31 0
|
4月前
|
JSON Java Serverless
函数计算产品使用问题之如何使用Go SDK从HTTP上下文中提取JSON数据
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
4月前
|
JSON 前端开发 JavaScript
Go怎么解析不定JSON数据?
在Go中处理不确定结构的JSON数据,可以使用`map[string]interface{}`来解析,它能适应各种JSON键值对,但需要类型检查。另一种方法是使用`json.RawMessage`保存原始JSON,之后按需解析。此外,`json.Number`用于处理任意精度的数字。当JSON字段类型未知时,可以先解码到`interface{}`并做类型断言。第三方库如gjson和jsonparser提供更灵活的解析选项。
|
6月前
|
JSON JavaScript 前端开发
Golang深入浅出之-Go语言JSON处理:编码与解码实战
【4月更文挑战第26天】本文探讨了Go语言中处理JSON的常见问题及解决策略。通过`json.Marshal`和`json.Unmarshal`进行编码和解码,同时指出结构体标签、时间处理、omitempty使用及数组/切片区别等易错点。建议正确使用结构体标签,自定义处理`time.Time`,明智选择omitempty,并理解数组与切片差异。文中提供基础示例及时间类型处理的实战代码,帮助读者掌握JSON操作。
172 1
Golang深入浅出之-Go语言JSON处理:编码与解码实战
|
5月前
|
JSON Go 数据格式
go之json使用
go之json使用
|
6月前
|
JSON 编解码 Go
【Go语言专栏】Go语言中的JSON编码与解码
【4月更文挑战第30天】Go语言内置JSON编码解码支持,简化了数据交换。`json.Marshal`用于将Go结构体转换为JSON,如示例中`Person`结构体的编码。`json.Unmarshal`则将JSON数据反序列化到结构体,需传入结构体变量的地址。错误处理至关重要,特别是在处理大量数据时,要注意性能优化,如避免不必要的转换和重复操作。了解自定义编码解码和最佳实践能提升开发效率。掌握这些技能,有助于构建高效Go应用。
69 0
|
11月前
|
JSON Go 数据格式
go 变量与json相互转换
go 变量与json相互转换
66 1
|
JSON Linux 测试技术
go语言处理数据、基本通信以及环境配置 -- json,protobuf,grpc
go语言处理数据、基本通信以及环境配置 -- json,protobuf,grpc
|
存储 XML JSON
互联网协议必备:Go语言中JSON的序列化与反序列化
互联网协议必备:Go语言中JSON的序列化与反序列化
147 0