math/big.int 是唯一能真正防止整数溢出的方案,但需调用 add、mul 等方法而非运算符,且 json 大数解析必须用字符串或 json.number 避免 float64 精度丢失。

math/big.Int 是唯一能真正防止整数溢出的方案。用 int64 或 float64 处理大数,不是“可能出错”,而是“必然 silently 错”——加减乘后值变负、精度丢位、JSON 解出来是错数,连 panic 都不会给你。
big.Int 不能用 + - * / 运算符
Go 不支持运算符重载,所有算术必须调方法:Add、Mul、Exp 等。写 a + b 直接编译失败。
-
a.Add(a, b)是原地修改a,返回*big.Int指针(还是a自己) - 想链式计算?得显式传目标变量:
tmp := new(big.Int).Mul(x, y).Add(tmp, z) - 别写
z := new(big.Int); z = big.NewInt(42)—— 前面的z泄漏了,应统一用big.NewInt(42)或复用对象
SetString 进制参数不写 0 就不是自动识别
从 hex 字符串(如 "0xabc")或 JSON 字段解析时,SetString(s, 0) 只认小写 "0x" 前缀,不认 "0X"、空格、或带前导零的十进制("00123" 会被当八进制)。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 十六进制:用
z.SetString("abc", 16)或z.SetString("0xabc", 0)(仅限小写 0x) - 十进制字符串:务必指定
10,否则"00123"→ 八进制 → 值变成 83 -
SetString返回(\*big.Int, bool),!ok表示解析失败,必须检查,它不会 panic
JSON 里大数默认转 float64,精度早丢了
前端发 {"id": 12345678901234567890},Go 层拿到的就是 float64,哪怕字段声明为 int64 或 big.Int,也救不回来——因为 JS 和 Go 的 float64 都只有 53 位精度,超过 2^53 - 1(约 9e15)就必然丢位。
- 最稳做法:前后端约定大数字段一律传字符串,Go 字段加
,string标签:ID string `json:"id,string"` - 若无法改前端,用
json.Number接收:ID json.Number `json:"id"`,再调ID.Int64()(超范围会 error)或ID.String()传给big.Int.SetString(..., 10) - 泛型 map 场景必须用
json.NewDecoder(r).UseNumber(),但注意它不递归转换嵌套结构,map[string]interface{}里的数字仍是float64,得手动遍历处理
Exp 计算幂时模数 nil 才是普通幂
别被 Exp 方法签名误导:func (z *Int) Exp(x, y, m *Int) *Int 中第三个参数 m 是模数。如果要做 2^1000 这种纯幂运算,m 必须传 nil,否则算的是 (x^y) mod m。
- 正确写法:
result.Exp(base, exp, nil) - base 和 exp 本身也得是
*big.Int,不能传 int 字面量 - 指数为 0 时结果是 1;底数为 0 且指数 > 0 时结果是 0;底数为 0 且指数为 0 是未定义行为(
big.Int返回 1,但数学上无意义)
实际中最容易被忽略的,是 JSON 解析阶段的精度丢失——它发生在你拿到数据之前,big.Int 再强也无力回天。要么前端发字符串,要么 Go 层用 json.Number 拦住 float64 中转,二者缺一不可。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










