登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  Golang >  Go问答

Go strconv.ParseFloat 返回 ErrRange 时结果还能用吗

来源:17golang原创

时间:2026-10-05 06:45:57 145浏览 收藏

遇到 strconv.ParseFloat 返回 ErrRange 时,返回的浮点数通常不能当作正常业务值继续使用。对于语法合法但超出目标类型范围的输入,Go 会返回正无穷或负无穷,同时把错误包装在 *strconv.NumError 中。正确做法是先识别 ErrRange,再根据业务决定拒绝、告警或转入专门的溢出处理,而不是忽略 err。

要点速览
  • ErrRange 表示数字格式合法,但超出了 bitSize 指定的浮点范围;文档规定此时返回 ±Inf。
  • err != nil 时不要把返回值当作已验证的金额、比例或计数;用 errors.Is 判断底层错误。
  • bitSize=32 仍返回 float64,但解析按 float32 的精度和范围进行。
一句话判断:ErrRange 下的结果可以用于记录和诊断,但默认不应继续参加业务计算;只有业务明确允许无穷值时,才单独处理它。

先看清 ErrRange 返回了什么

把一个远超 float64 上限的十进制字符串传给解析器,可以观察到“值有返回、错误也有返回”的状态。这里的值不是被截断到某个最大有限数,而是无穷值。下面的代码只用于展示判断路径,代码块中的输出是预期示例。

package main

import (
    "errors"
    "fmt"
    "math"
    "strconv"
)

func main() {
    value, err := strconv.ParseFloat("1e400", 64)
    fmt.Printf("value=%v isInf=%v errRange=%v\\n",
        value, math.IsInf(value, 0), errors.Is(err, strconv.ErrRange))
    // ErrRange 表示输入语法成立,但目标浮点范围装不下它。
    if err != nil {
        var numErr *strconv.NumError
        if errors.As(err, &numErr) {
            fmt.Printf("func=%s num=%s cause=%v\\n", numErr.Func, numErr.Num, numErr.Err)
        }
    }
}
value=+Inf isInf=true errRange=true
func=ParseFloat num=1e400 cause=value out of range

官方 strconv 文档把这种情况定义得很明确:输入在语法上是合法浮点数,但距离目标大小的最大浮点数超过半个 ULP 时,返回 f = ±Inf 和 ErrRange。因此,返回值“存在”不等于解析“成功”。

Go strconv.ParseFloat 从合法数字输入到 ErrRange 与正无穷返回的边界说明图
图1:ParseFloat 数值范围说明图,展示合法输入、目标范围和 ErrRange 返回值的关系。

不要只用字符串比较错误

ParseFloat 返回的错误具体类型是 *strconv.NumError,其中的 Err 才是底层原因。Go 1.14 以后它支持 Unwrap,所以可以用 errors.Is(err, strconv.ErrRange) 判断。与之相对,输入含有非法字符、空字符串等情况属于 ErrSyntax,这两类错误的处理策略通常不同。

情况返回值特征建议
普通合法数字有限的 float64,err 为 nil按业务校验后使用
语法错误通常为 0,err 为 ErrSyntax提示输入格式或拒绝记录
范围溢出为 +Inf 或 -Inf,err 为 ErrRange拒绝进入普通计算链

不要依赖完整错误文本,例如 "value out of range" 只是底层错误的描述,包装文本还可能包含函数名和原始输入。判断类别用 errors.Is,需要记录原始输入时再通过 NumError.Num 获取。

把“能不能用”变成业务边界

解析层可以把技术错误转换成更清楚的业务错误。下面的包装函数同时拒绝溢出、NaN 和显式 Infinity,适合金额、比例、阈值等必须是有限数字的场景;如果你的业务允许无穷值,可以把对应分支改成专门的标记状态,但不要让它悄悄流入普通加减乘除。

package input

import (
    "errors"
    "fmt"
    "math"
    "strconv"
    "strings"
)

func ParseFiniteFloat(text string, bitSize int) (float64, error) {
    value, err := strconv.ParseFloat(strings.TrimSpace(text), bitSize)
    if err != nil {
        // 先区分范围错误和语法错误,避免把两者混成“解析失败”。
        if errors.Is(err, strconv.ErrRange) {
            return 0, fmt.Errorf("浮点数超出范围: %w", err)
        }
        return 0, fmt.Errorf("浮点数格式无效: %w", err)
    }
    if math.IsNaN(value) || math.IsInf(value, 0) {
        // NaN/Inf 可能是合法语法,但有限值业务通常不接受它们。
        return 0, errors.New("只允许有限浮点数")
    }
    return value, nil
}

这里把 TrimSpace、错误分类和有限值检查放在同一层,是为了让调用方只接收“已经满足解析边界”的结果。若输入来自 JSON、CSV 或表单,还应在上游保留原始字符串,方便把具体字段和原始值写入日志;日志中不要把错误当作可忽略信号。

Go ParseFloat 错误分类与有限值业务策略的静态关系说明图
图2:错误策略说明图,展示 ErrSyntax、ErrRange、NaN/Inf 与有限数值的分流边界。

bitSize 不只是返回类型开关

ParseFloat(s, 32) 的返回类型仍然是 float64,但解析时使用 float32 的精度和范围,结果可以安全转换为 float32。这意味着同一字符串在 32 和 64 下可能得到不同的舍入结果,甚至只在 32 下触发 ErrRange。调用时要让 bitSize 与最终存储类型一致,不能因为变量声明为 float64 就默认选择 64。

一个简单的复查清单是:确认输入是否允许 NaN 或 Inf;确认目标字段是 float32 还是 float64;确认 ErrRange 是否被转成了可观察的业务错误;最后检查计算前是否仍可能出现 math.IsInf 或 math.IsNaN。

相关问题

ErrRange 时能不能取返回值做日志?

可以。返回的 ±Inf 能帮助定位输入方向和溢出类型,但它应当被当作诊断信息,不是已经通过校验的业务数值。

ErrRange 和 ErrSyntax 能共用一套提示吗?

不建议。前者是范围不够,后者是格式不符合浮点语法;用户修复输入的方式不同,日志和重试策略也不同。

为什么不直接判断 value == math.Inf(1)?

因为还要覆盖负无穷,而且显式输入 Inf 可能没有错误。更稳妥的做法是先处理 err,再用 math.IsInf(value, 0) 检查业务是否允许无穷值。

参考:https://pkg.go.dev/strconv;官方文档中的 ParseFloat 说明了 ErrRange 与 ±Inf 的对应关系。工程代码里保留这条判断边界,通常比把异常值静默转换成某个“最大值”更安全。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>