math/big.int 必须用 new 或 big.newint 初始化,不可 var 声明;赋值需调用 setint64、setstring 等方法;运算如 add 为就地修改,目标变量需显式指定;比较须用 cmp 方法而非 ==。

math/big.Int 必须用 new 或 constructor 初始化,不能直接 var 声明
Go 的 math/big.Int 是结构体指针类型,内部字段(比如 abs)未初始化时为 nil。直接写 var x *big.Int 会得到一个 nil 指针,后续调用 x.SetInt64(42) 或 x.Add(...) 会 panic:"panic: runtime error: invalid memory address or nil pointer dereference"。
正确做法只有两种:
- 用
new(big.Int)分配零值对象:x := new(big.Int) - 用构造函数如
big.NewInt(n)(仅支持 int64 范围内初始值):y := big.NewInt(100)
注意:big.NewInt(0) 和 new(big.Int) 效果等价,都返回已初始化的、值为 0 的 *big.Int;但前者语义更清晰,推荐初值确定时优先用 big.NewInt。
赋值必须用方法,不能用 = 直接赋整数或字符串
math/big.Int 没有重载赋值操作符,所有“赋值”本质是调用方法修改自身。常见错误是写 x = 123(编译失败)或 x = big.NewInt(123)(虽能编译,但只是替换指针,原对象可能被意外复用)。
安全且符合设计意图的做法是:
- 从 int64 赋值:用
x.SetInt64(123) - 从字符串赋值(支持任意长度十进制或十六进制):用
x.SetString("12345678901234567890", 10),第二个参数是进制(10 或 16) - 从另一个
*big.Int复制:用x.Set(y)(深拷贝值,不共享底层数据)
漏掉 .Set* 直接赋值,要么编译报错,要么逻辑出错——比如误以为 x = y 是数值复制,实际只是指针别名,后续改 x 会影响 y。
运算结果要显式指定目标变量,避免意外覆盖
math/big.Int 所有算术方法(Add、Mul、Exp 等)都是就地修改(in-place),第一个参数是接收结果的目标。例如:z.Add(x, y) 表示 “把 x + y 的结果存入 z”,不是 “把结果赋给新变量”。
容易踩的坑:
- 写成
x.Add(x, y):把x自身加y后存回x,原x值丢失 - 写成
z := x.Add(x, y):语法错误,因为Add返回的是*big.Int(即z),但x.Add已经修改了x,且z就是x的别名 - 想保留原值又得结果?必须先用
z := new(big.Int).Set(x)复制一份再运算
典型安全模式:result := new(big.Int).Add(a, b) —— 一行完成分配 + 赋值 + 运算,无副作用。
大整数比较和布尔判断不能直接用 ==,要用 Cmp 方法
因为 *big.Int 是指针类型,x == y 比较的是地址是否相同,不是值是否相等。两个不同地址但值相同的 *big.Int,== 返回 false。
正确比较方式:
- 判相等:
x.Cmp(y) == 0 - 判大于:
x.Cmp(y) > 0 - 判小于:
x.Cmp(y)
Cmp 返回 -1 / 0 / 1,和 strings.Compare 语义一致。另外,big.Int 没有隐式转 bool,不能写 if x { ... };要判断是否非零,得用 x.Sign() != 0(Sign() 返回 -1/0/1)。
最常被忽略的是初始化和比较这两步——写完 var x *big.Int 就直接 x.SetString(...),或者用 == 判相等,然后程序在运行时崩溃或逻辑错得离谱。只要记住“指针需初始化、赋值靠方法、比较用 Cmp”,就能避开 90% 的坑。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











