You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go语言切片咨询:两种去重子集实现的代码差异及底层原理

Understanding Slice Mechanics in Your Go Subset Deduplication Code

Great question—let’s break down exactly why these implementations behave differently, focusing on how Go handles slices, since that’s the root of your confusion.

First Implementation: Full Slice Expression vs. Basic Truncation

Your first backtracking approach uses tempList = tempList[:len(tempList)-1:len(tempList)-1] to "undo" appends during backtracking. Let’s compare this to the simpler tempList[:len(tempList)-1] and why one works while the other fails.

How Go Slices Work Under the Hood

A Go slice is made up of three core components:

  • A pointer to an underlying array
  • A len (number of elements currently in use)
  • A cap (total space available in the underlying array)

When you use tempList[:len(tempList)-1], you’re creating a new slice that shares the same underlying array as the original. The new slice’s len is reduced by 1, but its cap stays identical to the original slice’s capacity.

Why tempList[:len(tempList)-1] Breaks Your Code

Here’s the critical issue: when you append tempList to result with *result = append(*result, tempList), you’re storing a reference to the slice (and its underlying array) in result. If you later modify that underlying array (by appending to a slice that shares it), every reference to that array will see the changes.

For example:

  1. You append [1,2] to result—this is a reference to the underlying array holding [1,2,...].
  2. You truncate tempList to [1] using tempList[:1]—this still points to the same array.
  3. You append 3 to tempList, which writes to the second position of the underlying array (since cap is still large enough), turning it into [1,3,...].
  4. The [1,2] you stored in result now becomes [1,3] because it’s referencing the same array—corrupting your final output.

Why tempList[:len(tempList)-1:len(tempList)-1] Works

The full slice expression a[low:high:max] sets the new slice’s cap to max - low. In your case, this means the truncated slice has a cap equal to its len (since max = len(tempList)-1 and low=0).

When you append to a slice where len == cap, Go will allocate a new underlying array instead of modifying the existing one. This breaks the shared reference chain:

  • The slice you stored in result keeps pointing to the original array.
  • Any future appends to tempList use a new array, so they don’t affect the already-stored slices in result.

Second Implementation: Using copy to Avoid Shared References

Your second approach sidesteps the problem entirely by creating a copy of the current result slice every time you add it to results:

newR := make([]int, len(result))
copy(newR, result)
results = append(results, newR)

Here, newR is a brand-new slice with its own underlying array, copied directly from result. Even if you modify the original result slice later (via append or truncate), the copy in results remains untouched. This is a more explicit way to prevent unintended side effects from shared slice references.

Key Takeaways

  • When storing slices in a result collection, always be mindful of whether you’re storing a reference or a copy.
  • The full slice expression (a[low:high:max]) lets you control a slice’s capacity, which can prevent accidental modifications to shared underlying arrays.
  • Using copy to create duplicate slices is a straightforward way to ensure your result entries stay immutable once added.

内容的提问来源于stack exchange,提问作者jack-nie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:45:00