Go语言中大整数需用big.Int,因无原生任意精度整数;int64上限为9223372036854775807,超限会溢出;math/big包提供big.Int支持大数运算,且为指针类型,操作需调用Add等方法。

Go 语言里大整数用 *big.Int,不是内置类型
Go 没有原生的任意精度整数,int64 最大只到 9223372036854775807。一旦超过这个值(比如计算 100!、RSA 密钥运算、哈希碰撞枚举),就会溢出或得到错误结果。必须显式使用标准库 math/big 包里的 *big.Int 类型。
注意:*big.Int 是指针类型,所有操作方法(如 Add、)都是**就地修改接收者**,不返回新对象——这点和字符串或 <code>time.Time 完全不同,容易误写成链式调用。
- 别写
x.Add(a, b).Mul(c, d)——Add返回的是*big.Int指针,但Mul是方法,不能直接链式调;更关键的是Add已经把x改了,后续再用x就不是原始值 - 正确做法是:分配独立变量,或用
new(big.Int)显式初始化后再传参 -
*big.Int零值是nil,未初始化就调.Add会 panic
从字符串或整数字面量创建 *big.Int 要小心进制和范围
不能直接用 big.NewInt(12345678901234567890) —— 字面量本身在编译期就被截断成 int64,早溢出了。必须用字符串初始化:
num := new(big.Int)
num.SetString("123456789012345678901234567890", 10) // 第二个参数是进制
常见错误:
- 忘记检查
SetString返回的bool结果,失败时num保持未定义状态 - 误传进制:比如把十六进制字符串传成
10,导致解析出错("ff".SetString("ff", 10)返回false) - 想用
big.NewInt处理大于math.MaxInt64的常量,结果数值已失真
除法、取模、幂运算要注意零值和性能
*big.Int 的 Div、Mod、Exp 方法对除零行为有明确定义,但和基础类型不同:
-
z.Div(x, y)当y == 0时,z被设为nil,不 panic —— 但后续任何方法调用都会 panic,得自己提前判空 -
Exp支持模幂(Exp(x, y, m)),这是密码学常用操作;但如果m == nil或m.Sign() == 0(即 m ≤ 0),结果是未定义的,文档没明确说 panic,实际运行可能 crash 或返回垃圾值 -
Exp在指数很大时很慢,没有自动优化(比如快速幂是内置的,但底数/模数极大时仍明显卡顿),别在热循环里算big.NewInt(2).Exp(...)百万次
和 JSON、数据库交互时 *big.Int 不是开箱即用的
标准 json.Marshal 不认识 *big.Int,直接序列化会得到 null 或 panic;SQL 驱动(如 lib/pq、mysql)通常也不支持直接 Scan 到 *big.Int。
- JSON 场景:要么自定义
MarshalJSON()方法,返回字符串(最安全);要么用中间string字段做桥接 - 数据库场景:多数驱动只支持扫描到
int64或string,得先Scan到string,再用SetString构造*big.Int - 别试图用
int64中转大数——又绕回溢出问题;也别用float64,精度丢失严重(比如1 转 <code>float64后再转回来可能是1)
真正麻烦的不是计算本身,而是数据进出时的隐式类型转换——这些地方最容易漏掉校验,上线后突然遇到一个超长数字就把服务搞挂。


















