【Golang】Json 无法表示 float64 类型的 NaN 以及 Inf 导致的 panic

【Golang】Json 无法表示 float64 类型的 NaN 以及 Inf 导致的 panic

原因

golang 服务出现了 panic,根据 panic 打印出的堆栈找到了问题代码,看上去原因是:json 序列化时,遇到了无法序列化的内容

[panic]: json: unsupported value: NaN or Infinite

在这里插入图片描述

NaN 以及 Infinite

解释:基本可以判断出:NaN 以及 Inf 是 float64 类型的两种特例,Json 无法表示这类数据,故 panic在这里插入图片描述

深度剖析

查阅 log 看到,这里最原始的 NaN 其实是字符串"NaN",明明是字符串,是如何将 "NaN"转变为 float64 的呢?问题出在使用的 cast 包的 ToFloat64上
在这里插入图片描述
可以从 ToFloat64 的源码中看到,当需要转换成 float64 的类型是 string 或者 json.Number 时,调用的都是 strconv.ParseFloat 函数(s.Float64 本质也是调用该函数),继续阅读 strconv.ParseFloat,我们可以在strconv/atof.go文件中看到以下代码:strconv.ParseFloat 会将字符串 NaN 以及 Inf 转换为 float64 类型的 NaN 以及 Inf。 而 json 无法处理这两种数据,会直接 panic在这里插入图片描述

修复

单独判断下即可

func SetValWhenFloatIsNaNOrInf(val float64) float64 {
   
	if math.IsNaN(val) {
   
		return 0.00
	}
	if math.IsInf(val, 0) {
   
		return 100.00
	}
	return val
}

扩展

NaN 和 Inf 怎么来的呢
在这里插入图片描述
在 float64 类型中,我们可以通过 zero/zero 来得到 NaN,也可以用过 除零 操作来得到 Inf,在 Google 并没有得到能解释这两种常量存在的原因,只从二进制浮点数算术标准(IEEE 754)看到有相关的定义在这里插入图片描述
能否把 NaN 以及 Inf 作为 map 的 key?
测试代码

func TestNaNKeyMap() {
   
	m := make(map[float64]struct{
   }, 0)
	for i := 0; i < 10; i++ {
   
		m[math.NaN()] = struct{
   }{
   }
		fmt.Printf("nan map len:%d\n", len(m))
	}
}
func TestInfKeyMap() {
   
	m := make(map[float64]struct{
   }, 0)
	for i := 0; i < 10; i++ {
   
		m[math.Inf(0)] = struct{
   }{
   }
		fmt.Printf("inf map len:%d\n", len(m))
	}
}

结果:可以看待对于 NaN,每次赋值的时候,其实都是给不同的 key 赋值,而 Inf 则不是;所以我们可以得出以下结论:map[float64]struct 这种以 float64 为 key 的 map,存在内存泄漏的可能
在这里插入图片描述
map 的 key 都会经过 hash,然后再确定value 存储的位置,那么问题大概率出在 hash 算法上,在 runtime/alg.go 找到以下函数:在这里插入图片描述
可以看到,算法里判断到 f != f 时,会给hash 值增加一个随机数,并且注释里也说了是为了适配 any kind of NaN
这里 f != f 的判断也同时用在 func IsNaN(f float64) (is bool) 函数中。

相关推荐

  1. C#三种小数类型 decimal和double , float

    2024-01-06 11:46:07       31 阅读
  2. python中tuple、intfloat内置方法

    2024-01-06 11:46:07       38 阅读
  3. float32、int8、uint8、int32、uint32之间区别

    2024-01-06 11:46:07       38 阅读
  4. 深入探索 Rust 中 Panic 机制

    2024-01-06 11:46:07       27 阅读
  5. 【Rust】——panic!和不可恢复错误

    2024-01-06 11:46:07       22 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-01-06 11:46:07       19 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-06 11:46:07       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-06 11:46:07       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-06 11:46:07       20 阅读

热门阅读

  1. 机器人相关知识

    2024-01-06 11:46:07       36 阅读
  2. 解析千兆多模光模块SFP-GE-SX

    2024-01-06 11:46:07       36 阅读
  3. 信息学奥赛一本通2067详解+代码

    2024-01-06 11:46:07       38 阅读
  4. 深入Pandas:数据分析的强大工具

    2024-01-06 11:46:07       35 阅读
  5. nlp中的transformer中的mask

    2024-01-06 11:46:07       43 阅读
  6. 一、Vue3基础[常用的循环]

    2024-01-06 11:46:07       41 阅读
  7. 基于SpringBoot的餐饮管理系统的设计与实现

    2024-01-06 11:46:07       45 阅读
  8. 222. 完全二叉树的节点个数

    2024-01-06 11:46:07       39 阅读
  9. Nginx网站服务

    2024-01-06 11:46:07       35 阅读
  10. 客户满意度调查常用的ChatGPT通用提示词模板

    2024-01-06 11:46:07       36 阅读
  11. 1001 害死人不偿命的(3n+1)猜想

    2024-01-06 11:46:07       35 阅读