Golang中结构体内部big.Int调用Exp后值异常变更问题
问题:值拷贝 big.Int 后调用 Exp 方法,原变量意外被修改
type Decimal struct { c big.Int // coefficient q big.Int // exponent } a := big.NewInt(1) b := big.NewInt(2) d := Decimal{*a, *b} d.c.Exp(big.NewInt(11), big.NewInt(2), big.NewInt(0)) fmt.Println(a, b, d) // 输出:11 2 {{false [121]} {false [2]}}
构造 Decimal 实例 d 时已通过 *a 完成值拷贝,修改 d.c 后,原变量 a 的值却变成了 Exp 方法第一个参数的值,预期 a 应保持不变。补充:打印 a、b、d.c、d.q 的指针地址,发现前后均不相同。
原因与解决办法
原因
这是 Go 标准库 big.Int 的内存复用优化导致的:
当调用 x.Exp(y, z, m) 时,如果参数 y 是临时创建的 big.Int(比如代码中的 big.NewInt(11)),标准库会直接复用 y 的底层数组存储计算结果,减少内存分配开销。
而 big.NewInt 会缓存一些小整数对应的 big.Int 实例(比如 1、11 这类),a := big.NewInt(1) 得到的指针,指向的正是缓存中的某个实例。当 Exp 方法复用临时变量 big.NewInt(11) 的底层内存时,恰好覆盖了缓存中 a 指向的那个实例的值,最终导致打印 a 时看到被修改后的结果。
虽然你对 a 做了值拷贝给 d.c,但 a 本身是指向缓存实例的指针,缓存实例被修改后,a 的输出自然跟着变。
解决办法
- 方法一:绕开
big.NewInt的缓存,用SetInt64创建独立实例:a := new(big.Int).SetInt64(1) - 方法二:确保
d.c和a指向的实例完全隔离,拷贝时显式分配新内存:d := Decimal{*new(big.Int).Set(a), *b}
内容的提问来源于stack exchange,提问作者1m1
相关产品推荐
相关产品推荐

