recover无法捕获数学溢出引发的panic,因为go中整数/浮点数溢出不会触发panic,而是静默回绕或产生非预期值;它只能捕获显式panic(如除零、非法字符)和运行时错误(如nil指针解引用、切片越界)。

recover 不能处理数学溢出引发的 panic —— Go 的整数/浮点数溢出**不会触发 panic**,而是静默回绕或产生非预期值。你真正需要防的,是公式解析阶段的显式 panic(比如除零、非法字符、括号不匹配),以及运行时错误(如 nil 指针解引用、切片越界)。
为什么 math overflow 不会触发 panic
Go 默认不检查算术溢出。例如:
var x int64 = math.MaxInt64 x++ // 结果是 math.MinInt64,无 panic,无警告
这意味着你在双栈求值中做 a + b 或 a * b 时,即使结果溢出,recover 也捕获不到任何东西——因为根本没 panic。
- 编译期
-gcflags="-d=checkoverflow"只对常量表达式有效,对变量计算无效 -
unsafe或反射无法通用检测溢出;Go 没有运行时溢出中断机制 - 如果你看到“overflow panic”,那一定是你自己写的
panic("overflow"),不是语言行为
recover 能捕获哪些公式计算中的 panic
它只对以下**明确由 panic() 调用或运行时错误触发**的崩溃有效:
-
panic("division by zero")(你手动加的除零检查) -
index out of range(解析字符串时s[i]越界) -
invalid memory address or nil pointer dereference(比如未初始化的*token) -
interface conversion: interface {} is nil, not float64(类型断言失败) -
runtime error: invalid memory address or nil pointer dereference(栈上指针为空)
这些才是 defer func() { recover() }() 能兜住的点。
正确包裹公式求值函数的 recover 模式
别在每层解析函数里都加 defer —— 只在最外层入口(如 Evaluate)加一次,否则嵌套 recover 会掩盖问题位置:
func Evaluate(expr string) (float64, error) {
defer func() {
if r := recover(); r != nil {
// 记录原始 panic 值,不要只打 "recovered"
log.Printf("formula panic in %q: %+v", expr, r)
}
}()
nums, ops := []float64{}, []rune{}
// ... 双栈解析逻辑(此处可能 panic)
return calcFinal(nums, ops), nil
}
- 必须用命名返回值或显式
err变量传递错误,recover()本身不设 err - 如果解析中调用了
panic("unmatched ')')",这里能捕获;但溢出导致的错误值(如1e308 * 1e308 = +Inf)不会触发 panic,需单独检查 - 不要在
calcOne内部加 defer —— 那会让 panic 位置模糊,调试困难
溢出实际该怎么做:检查 + 显式 panic + recover 兜底
想防数值爆炸,得自己写安全运算,并在越界时主动 panic,再靠外层 recover 捕获:
func safeMul(a, b float64) float64 {
if math.IsInf(a, 0) || math.IsInf(b, 0) || math.IsNaN(a) || math.IsNaN(b) {
panic("invalid operand in formula")
}
res := a * b
if math.IsInf(res, 0) || math.IsNaN(res) {
panic("arithmetic overflow in multiplication")
}
return res
}
- 浮点数用
math.IsInf/math.IsNaN检查,整数用math.MaxInt64 - b 类似逻辑 - 所有
safe*函数统一 panic 字符串格式,便于recover后分类处理 - 注意:
recover后函数立即 return,原计算流程不可继续;你要返回默认值或 error,而不是“重试”
真正容易被忽略的是:你以为在防溢出,其实大多数 panic 来自字符串索引、类型断言、空指针——那些地方才最该加 recover,而不是盯着 a + b 看。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











