Go基础面试题, Go 语言 slice 的 len,cap 和共享及扩容机制是什么?
Go基础面试题, Go 语言 slice 的 len,cap 和共享及扩容机制是什么?
QA
Step 1
Q:: Go语言 slice 的 len、cap 和共享及扩容机制是什么?
A:: Go语言中的slice是对数组的抽象封装,具有动态变化的特性。slice的len表示当前slice中元素的数量,而cap表示底层数组的容量。len和cap可以通过内置函数len()和cap()
获取。slice的扩容机制基于底层数组的重新分配:当新增元素导致超出cap时,Go会分配一个更大的底层数组(通常是当前cap的两倍),并将原有数据复制到新数组中。需要注意的是,多个slice可以共享相同的底层数组,从而影响彼此的修改。
Step 2
Q:: slice 在 Go 语言中是如何实现共享底层数组的?
A:: 在 Go 语言中,slice 是由一个指向底层数组的指针、长度(len)和容量(cap)组成的结构体。多个 slice 可以引用同一个底层数组,但它们的 len 和 cap 可以不同。因此,一个 slice 的修改可能会影响共享同一底层数组的其他 slice。这种共享机制可以通过 slice 表达式,如 a = b[:len(b):cap(b)]
,在使用过程中精确控制切片的行为。
Step 3
Q:: Go 语言 slice 的扩容是如何决定新容量的?
A:: Go 语言中 slice 的扩容机制遵循一定的规则:当容量小于 1024 时,新的容量是现有容量的两倍;当容量大于等于 1024 时,新的容量将增加原来容量的 25
%。这种扩容策略可以平衡性能和内存使用。当 slice 需要超出 cap 进行扩容时,底层会分配一个新的更大容量的数组,并将原数据复制到新数组中。
Step 4
Q:: 如何在 Go 语言中避免 slice 扩容带来的性能问题?
A:: 为了避免频繁的 slice 扩容导致的性能问题,开发者可以提前估算出所需的容量,并使用 make 函数初始化 slice 时直接指定容量。例如,make([]int, 0, 1000) 预分配了 1000
的容量,这样可以避免后续操作中频繁扩容带来的性能损耗。此外,开发者也可以通过使用 append 的技巧来控制扩容的频率,如将多个元素一次性 append 以减少扩容的次数。