Go 的 big.Int 类型在循环中直接追加到切片时,因内部底层数组共享导致值被意外覆盖;需显式调用 Set() 方法实现逻辑深拷贝,而非依赖赋值或 append() 的浅复制行为。
go 的 `big.int` 类型在循环中直接追加到切片时,因内部底层数组共享导致值被意外覆盖;需显式调用 `set()` 方法实现逻辑深拷贝,而非依赖赋值或 `append()` 的浅复制行为。
在 Go 中,big.Int 是一个结构体,其核心字段 abs(绝对值)类型为 nat(即 []Word,本质是底层字节切片),而切片本身包含指向底层数组的指针。这意味着:对 big.Int 的赋值(如 primes = append(primes, i))仅复制结构体头部(含指针),并不复制其指向的底层数组——即发生的是“浅拷贝”。
因此,在原始代码中:
primes = append(primes, i) // ❌ 浅拷贝:所有元素共享同一份底层数据 i.Add(&i, &one) // 后续修改 i 会污染之前 append 进去的所有副本
循环每次迭代复用同一个 i 实例,append 存入切片的只是 i 的结构体副本(含指向同一 nat 数组的指针)。当 i.Add() 修改其内部数值时,所有已追加的“副本”因共享底层数组,其值同步被覆盖——最终切片中四个元素全部显示为最后一次的 5。
✅ 正确做法是:为每个要保存的值创建独立的 big.Int 实例,并通过 .Set() 显式复制数值:
func primesLessThan(n *big.Int) []big.Int {
var one, i big.Int
one.SetInt64(1)
i.SetInt64(1)
var primes []big.Int
for i.Cmp(n) <blockquote><p>? 提示:new(big.Int).Set(&src) 是惯用写法,等价于先声明 var p big.Int 再 p.Set(&src),语义清晰且避免零值隐患。</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/learn/7564" title="使用Go语言搭建家庭相册系统-相关课件"><img
src="https://img.php.cn/upload/webcode/000/000/164/636a2b4d84031727.png" alt="使用Go语言搭建家庭相册系统-相关课件" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/learn/7564" title="使用Go语言搭建家庭相册系统-相关课件" class="overflowclass">使用Go语言搭建家庭相册系统-相关课件</a>
<p class="overflowclass">使用Go语言搭建家庭相册系统-相关课件</p>
</div>
<a rel="nofollow" href="/xiazai/learn/7564" title="使用Go语言搭建家庭相册系统-相关课件" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div></blockquote><p>同样地,针对问题中提到的“赋值引发副作用”场景:</p><pre class="brush:php;toolbar:false;">one := big.NewInt(1)
two := big.NewInt(2)
one = two // ❌ 错误!这不是赋值,而是指针重绑定(two 是 *big.Int)
one.SetInt64(3) // 影响 two,因 one 和 two 指向同一对象
此处 one = two 实际是将 *big.Int 指针重新赋值,二者指向同一内存地址。若需独立副本,必须使用 .Set():
one := big.NewInt(1) two := big.NewInt(2) one.Set(two) // ✅ 深拷贝数值:one 和 two 独立,互不影响 one.SetInt64(3) fmt.Println(one.String(), two.String()) // 输出: "3" "2"
? 总结关键原则:
- big.Int{} 或 new(big.Int) 创建新实例,但初始值为零;
- x.Set(y) 是安全深拷贝数值的标准方法;
- 避免直接对 *big.Int 变量赋值(a = b),这仅改变指针指向;
- 在循环中构建 big.Int 切片时,务必为每个元素调用 .Set() 或 new(big.Int).Set()。
掌握这一机制,可避免大量因 big.Int 浅拷贝引发的隐蔽逻辑错误。










