【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) 函数中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/326729.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

转后端一年半双非本科Java无实习进大厂,给双非朋友经验分享

背景介绍 B站有详细视频&#xff0c;同名搜索即可。 今天文章想分享的是我踩过的坑以及那些做的是值得大家参考。 有需要就加V&#xff1a; zhazhagao_ 进了快手(如果你觉得不是大厂那就不是!)&#xff1a; 真双非本科: 安徽某双非无实习: 因为编程语言问题,去过之后发现不喜欢…

Spark 运行架构

Spark 框架的核心是一个计算引擎&#xff0c;整体来说&#xff0c;它采用了标准 master-slave 的结构。 如下图所示&#xff0c;它展示了一个 Spark 执行时的基本结构。图形中的 Driver 表示 master&#xff0c; 负责管理整个集群中的作业任务调度。图形中的 Executor 则是 sla…

netcore html to pdf

一、新建项目&#xff1a;QuestPDFDemo <PackageReference Include"NReco.PdfGenerator" Version"1.2.1" /> 二、上代码 using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging;using QuestPDFDemo.Models; using System; using Sys…

WEB 3D技术 three.js 包围盒

本文 我们来说 包围盒 如下图所示 就是一个方框 框住我们整个物体 它的作用 比较明显的就是 当用户点击某个物体 我们用包围盒套住 用户能够很直观的知道自己当前选中的物体是哪一个 还有就是 比如 我们物体做的比较复杂 是非常多顶点构建的 那么 我们判断它有没有和其他物体…

第14课 用openCV数豆豆

除了检测运动&#xff0c;openCV还能做许多有趣且实用的事情。其实openCV和FFmpeg一样都是宝藏开源项目&#xff0c;貌似简单的几行代码功能实现背后其实是复杂的算法在支撑。有志于深入学习的同学可以在入门后进一步研究算法的实现&#xff0c;一定会受益匪浅。 这节课&#…

Flutter3.X基础入门教程(2024完整版)

Flutter介绍&#xff1a; Flutter是谷歌公司开发的一款开源、免费的UI框架&#xff0c;可以让我们快速的在Android和iOS上构建高质量App。它最大的特点就是跨平台、以及高性能。 目前Flutter已经支持 iOS、Android、Web、Windows、macOS、Linux的跨平台开发。 教程所讲内容支持…

软件测试|什么是Python构造方法,构造方法如何使用?

构造方法&#xff08;Constructor&#xff09;是面向对象编程中的重要概念&#xff0c;它在创建对象时用于初始化对象的实例变量。在Python中&#xff0c;构造方法是通过特殊的名称__init__()来定义的。本文将介绍Python构造方法的基本概念、语法和用法。 什么是构造方法&…

C++面试宝典第14题:结构体和位域对齐

题目 阅读下面的代码段,并给出程序的输出(使用Visual Studio 2019编译器)。 #include <stdio.h> #include <string.h>struct TData {int a:3;int b:3;int c:3;int d:6;double e;short f; };int main() {printf("%d\n", (int)sizeof(TData));TData da…

软件测试|Windows系统安装Cypress教程

前言 每当提起web自动化测试&#xff0c;大家首先想到的就是selenium&#xff0c;最近这两年时间&#xff0c;出现了playwright和cypress这两款新的工具&#xff0c;不过现在应用范围还是不如selenium&#xff0c;之前我们介绍了playwright的使用&#xff0c;现在开始&#xf…

生态系统服务构建生态安全格局中的实践技术应用

生态安全是指生态系统的健康和完整情况。生态安全的内涵可以归纳为&#xff1a;一&#xff0c;保持生态系统活力和内外部组分、结构的稳定与持续性&#xff1b;二&#xff0c;维持生态系统生态功能的完整性&#xff1b;三&#xff0c;面临外来不利因素时&#xff0c;生态系统具…

GPT/GPT4科研应用与AI绘图技术及论文高效写作教程

详情点击链接&#xff1a;GPT/GPT4科研实践应用与AI绘图技术及论文高效写作教程 一OpenAI 1.最新大模型GPT-4 Turbo 2.最新发布的高级数据分析&#xff0c;AI画图&#xff0c;图像识别&#xff0c;文档API 3.GPT Store 4.从0到1创建自己的GPT应用 5. 模型Gemini以及大模型…

软件测试|全面解析Docker Start/Stop/Restart命令:管理容器生命周期的必备工具

简介 Docker是一种流行的容器化平台&#xff0c;用于构建、分发和运行应用程序。在使用Docker时&#xff0c;经常需要管理容器的生命周期&#xff0c;包括启动、停止和重启容器。本文将详细介绍Docker中的docker start、docker stop和docker restart命令&#xff0c;帮助您全面…