go处理超大整数必须全程使用*big.int,初始化仅限setstring(s,10)并校验返回值,运算全靠方法(如add),输出用text(10),复用实例以减gc压力。

Go 语言中处理超大整数,核心就一条:绕过所有内置整型和字符串转数字的“快捷函数”,全程用 *big.Int + 字符串初始化 + 显式方法调用。这不是权衡,而是必须——因为 int64、float64、strconv.Atoi、strconv.ParseInt 全部会在几百位前彻底失效。
初始化必须用 SetString,且严格校验
不能写 big.NewInt(1234567890123456789012345),编译直接报错;也不能依赖 strconv.ParseInt(s, 10, 64) 中转,它早就在进 big.Int 之前就溢出了。
- 唯一安全入口是
a.SetString(s, 10),第二个参数必须显式传进制(十进制传 10,十六进制去掉 "0x" 后传 16) - 输入字符串必须先
strings.TrimSpace(),空格、换行、BOM 都会导致SetString静默返回false - 务必检查返回值:
if _, ok := a.SetString(s, 10); !ok { return fmt.Errorf("invalid number: %q", s) },不检查等于埋雷
运算全部调方法,没有操作符
*big.Int 是指针类型,不支持 +、-、*、/。所有计算都靠方法,而且全是就地修改。
- 加法:
c.Add(a, b)把a+b写进c;a.Add(a, b)会直接改掉a的值 - 想保留原值?用
new(big.Int).Set(a).Add(new(big.Int), b),或拆成两步:tmp := new(big.Int).Set(a); result := tmp.Add(tmp, b) - 链式调用可行但需谨慎:
res := new(big.Int).Add(a, b).Mul(c, d)是合法的,前提是res是新分配对象
输出必须用 Text(10),别信 fmt.Println
fmt.Println(sum) 实际调的是 sum.String(),而 String() 对极大数可能返回科学计数法(如 1.23e+200),这不是 bug,是设计行为。
- 要纯十进制数字字符串,必须用
sum.Text(10)—— 参数是进制,不是小数位数 - 要字节切片?用
sum.Bytes(),注意这是大端二进制编码,不是 ASCII 数字串 - JSON 序列化需手动包装:实现
MarshalJSON返回text(10)字符串,UnmarshalJSON再用SetString解析
性能与复用要注意 GC 压力
高频循环中反复 new(big.Int) 会显著增加垃圾回收负担,尤其在密码学或批量计算场景。
- 推荐复用变量:提前声明
a, b, sum := new(big.Int), new(big.Int), new(big.Int),在循环内重复调SetString和Add - 更进一步可配
sync.Pool缓存*big.Int实例,但注意每次取出后必须.SetInt64(0)或.Set(nil)清零,否则残留值会污染后续计算 - 避免在热路径中做无谓拷贝,比如不需要保留原值时,别写
tmp := new(big.Int).Set(a)再算,直接原地操作更高效
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











