Go中int64溢出静默回绕,需用math/big处理大数:从字符串构造、复用实例、检查SetString返回值、避免频繁转换,JSON/DB存为字符串。

为什么 int64 算着算着就变负数了
不是溢出警告,而是静默回绕——Go 的内置整型不会 panic,int64 加到 9223372036854775807 再加 1 就变成 -9223372036854775808。你查日志、对数据,发现结果“莫名其妙”,其实只是没切换到任意精度上下文。
这时候必须换 math/big:它用切片存数字,不依赖 CPU 寄存器位宽,只要内存够,就能算 10^1000000。
- 别在循环里反复创建
big.Int实例,复用new(big.Int)或提前声明变量,避免 GC 压力 -
big.Int是值类型但内部含指针,传参时用指针(*big.Int)更安全,尤其要修改原值时 - 所有运算方法(如
Add、Mul)都是就地修改,返回的是接收者本身,不是新对象
big.Int 初始化总出错:字符串、十进制、十六进制怎么填
常见错误是直接写 big.NewInt(9999999999999999999) ——这行代码根本过不了编译,因为字面量超出了 int64 范围,编译器先报错。
正确路径只有一条:从字符串构造。
立即学习“go语言免费学习笔记(深入)”;
- 十进制大数:
new(big.Int).SetString("123456789012345678901234567890", 10) - 十六进制(比如哈希值):
new(big.Int).SetString("a1b2c3...", 16) - 八进制、二进制同理,第二个参数改对应进制即可(2 / 8 / 16)
- 返回值是
(*big.Int, bool),第二个布尔值必须检查!解析失败时返回nil, false,不判会 panic
性能差得离谱?你可能在频繁分配和转换
把 big.Int 当普通整型用,比如在 hot loop 里反复调 .Int64() 或 .String(),很容易成为瓶颈。前者在值超出 int64 范围时 panic;后者每次调用都分配新字符串,GC 频繁。
- 需要比较大小?用
a.Cmp(b),返回 -1/0/1,比转成字符串再==快一个数量级 - 要取模?直接用
a.Mod(a, b),别先转int64再取模——那已经不是同一个数学对象了 - 批量计算时,预分配
big.Int变量池,或用big.Int.Set()复用内存,避免每次 new - 注意
big.Float和big.Rat是另一套开销模型,别误用它们处理纯整数问题
JSON 和数据库字段怎么存 big.Int
标准 json.Marshal 不认识 *big.Int,直接序列化会得到空对象 {} 或 panic;数据库驱动(如 lib/pq、mysql)也大多只认 int64 或 string。
- JSON 场景:实现
MarshalJSON()方法,统一转成字符串("12345678901234567890"),前端/其他服务按字符串解析 - 数据库场景:字段类型设为
TEXT或VARCHAR,读写时用.Text(10)和SetString(..., 10) - 别用
int64中间桥接——一旦原始值 > 9223372036854775807,信息就永久丢失 - PostgreSQL 的
NUMERIC类型可原生支持,但 Go 驱动仍需手动注册Scan/Value方法,否则还是当字符串处理
最常被忽略的点:几乎所有涉及输入解析的地方(HTTP query、JSON body、CSV 行),都要默认走 SetString + 进制校验,而不是试图“兼容 int64”。一旦放松,边界 case 就在生产环境凌晨三点出现。










