面试题答案
一键面试- 基本原理
- Go语言的切片(slice)是一种动态数组,其底层数据结构包含一个指向数组的指针、切片的长度(len)和容量(cap)。当切片需要扩容时,会创建一个新的更大的底层数组,然后将原切片的数据复制到新的底层数组对应的位置上。
- 扩容倍数规则
- 一般情况:当原切片的容量小于1024时,新的容量会直接翻倍。例如,原切片容量为100,扩容后容量变为200。在这种情况下,数据迁移过程相对直接,会按照原切片元素的顺序,从第一个元素开始,依次将每个元素复制到新切片对应位置。比如原切片
s := []int{1, 2, 3}
,扩容后新切片底层数组有足够空间,将1复制到新数组第一个位置,2复制到第二个位置,3复制到第三个位置。 - 大容量情况:当原切片的容量大于或等于1024时,新的容量会增加原容量的1/4。例如,原切片容量为2048,扩容后容量变为
2048 + 2048/4 = 2560
。在数据迁移时,同样是按顺序复制元素,但由于新的扩容策略,新切片底层数组的增长幅度相对较小,在复制过程中,会根据新容量分配的空间,有序地将原切片元素填充进去。
- 一般情况:当原切片的容量小于1024时,新的容量会直接翻倍。例如,原切片容量为100,扩容后容量变为200。在这种情况下,数据迁移过程相对直接,会按照原切片元素的顺序,从第一个元素开始,依次将每个元素复制到新切片对应位置。比如原切片
- 特殊情况及差异
- 不同类型切片:不同类型的切片在数据迁移时,本质上都是按顺序复制元素,但由于类型不同,复制操作会有不同的实现细节。例如,对于结构体类型的切片,复制时会按结构体的内存布局,完整地将每个结构体对象从原位置复制到新位置,包括结构体内部的所有字段。如果结构体中包含指针类型字段,指针指向的数据不会被重新分配,只是指针值被复制。而对于基本类型(如
int
、float
等)的切片,直接按值复制即可。 - 并发操作:如果在扩容过程中有并发读写切片的操作,可能会导致数据竞争问题。在这种情况下,数据迁移可能无法正确完成,因为原切片数据在复制过程中可能被并发修改,新切片复制到的数据可能是不一致的。为避免这种情况,通常需要使用同步机制(如
sync.Mutex
)来保护切片的读写操作。
- 不同类型切片:不同类型的切片在数据迁移时,本质上都是按顺序复制元素,但由于类型不同,复制操作会有不同的实现细节。例如,对于结构体类型的切片,复制时会按结构体的内存布局,完整地将每个结构体对象从原位置复制到新位置,包括结构体内部的所有字段。如果结构体中包含指针类型字段,指针指向的数据不会被重新分配,只是指针值被复制。而对于基本类型(如