编程Go 程序员

在 Go 中,内置函数 append、len 和 cap 是什么,它们在语言层面上如何工作,以及使用切片时存在哪些隐患?

用 Hintsage AI 助手通过面试

回答

在 Go 中,内置函数 appendlencap 在处理切片时起着关键作用。

  • len(slice) 返回切片中的元素数量。
  • cap(slice) 返回切片的容量——在分配新内存之前的最大元素数量。
  • append(slice, elems ...T) 在容量不足时会创建一个新数组(以及新的后备存储),这可能会意外改变切片的传递语义。

示例:

arr := []int{1,2,3} arr2 := append(arr, 4) // arr2 可能在同一个或新的后备数组中,具体取决于 cap(arr)

细节:

  • 如果你对一个从其他切片(或原始数组)“切出”的切片进行 append,可能会出现副作用:原始数据会被修改。
  • 在函数中传递切片时,len/cap 仅作用于“可见”的部分。
  • 在超过 cap 时进行 append 会创建一个新数组,旧数组保持不变。

拖延的问题

如果对切片“切掉”一部分并通过 append 添加元素,会影响原始数组吗?

回答:如果 cap 允许,append 会将元素“写入”原始数组的末尾,所有引用同一数组的切片都能看到这些变化。

示例:

a := []int{1,2,3,4} b := a[:2] // [1 2], len=2, cap=4 b = append(b, 10) // a 发生变化: a -> [1, 2, 10, 4]

实际错误示例


故事

团队在子切片中添加元素,结果父数组中的数据意外改变——这导致了业务逻辑不协调,并在用户之间的任务分配中造成了难以调试的错误。


故事

在对一个大切片多次调用 append 时,期望新数组一直重新分配,但实际上,系统的几个部分继续使用同一个“后备数组”,引发了竞争条件和数据损坏。


故事

开发者使用 make 分配固定大小的切片,但错误地交换了参数位置:make([]int, cap, len)。结果,关注容量的逻辑意外地按长度工作,导致在超出 s[0:len] 时出现恐慌。