面试题答案
一键面试- 切片结构:
- 在Go语言中,切片是一个包含三个字段的结构体:指向底层数组的指针、切片的长度(
len
)和切片的容量(cap
)。 - 例如,对于切片
s := []int{1, 2, 3}
,它有一个指向包含[1, 2, 3]
的底层数组的指针,长度len(s)=3
,容量cap(s)
一般初始化为3(如果没有后续操作扩容,这里假设是3)。
- 在Go语言中,切片是一个包含三个字段的结构体:指向底层数组的指针、切片的长度(
- 内存分配:
- 当调用
func modifySlice(s []int)
函数并在函数内部进行扩容操作时:- 如果当前切片的容量不足以容纳新的元素,Go语言会重新分配内存。它会分配一个更大的底层数组,然后将原底层数组的内容复制到新的底层数组中。
- 例如,原切片
s
容量为3,现在要增加到4个元素,就需要重新分配内存。新的底层数组大小可能是原容量的2倍(不同版本的Go语言扩容策略可能有差异,一般是2倍),即新容量为6,然后将原数组[1, 2, 3]
复制到新数组的前3个位置。
- 当调用
- 对原切片的影响:
- 一般情况:
- 如果函数内部的扩容操作导致了新的内存分配(即原容量不足),那么函数内部的切片
s
和调用处传入的原切片虽然开始时指向同一个底层数组,但扩容后就指向不同的底层数组了。此时,函数内部对切片s
的赋值操作不会影响调用处传入的原切片。 - 例如:
- 如果函数内部的扩容操作导致了新的内存分配(即原容量不足),那么函数内部的切片
- 一般情况:
package main
import "fmt"
func modifySlice(s []int) {
newS := append(s, 4)
newS[0] = 100
fmt.Println("Inside function:", newS)
}
func main() {
s := []int{1, 2, 3}
modifySlice(s)
fmt.Println("Outside function:", s)
}
在上述代码中,modifySlice
函数内部的append
操作导致了新的内存分配(因为原容量3不足以容纳4个元素),所以函数内部修改后的切片和原切片是相互独立的,输出为:
Inside function: [100 2 3 4]
Outside function: [1 2 3]
- 特殊情况:
- 如果函数内部的操作没有导致新的内存分配(即原容量足够),那么函数内部对切片的赋值操作会影响调用处传入的原切片。
- 例如:
package main
import "fmt"
func modifySlice(s []int) {
s[0] = 100
fmt.Println("Inside function:", s)
}
func main() {
s := make([]int, 3, 6)
s[0] = 1
s[1] = 2
s[2] = 3
modifySlice(s)
fmt.Println("Outside function:", s)
}
在这个例子中,make([]int, 3, 6)
创建的切片容量为6,modifySlice
函数内部对s
的修改会影响原切片,输出为:
Inside function: [100 2 3]
Outside function: [100 2 3]
综上所述,若函数内部扩容导致新内存分配,原切片不受影响;若未导致新内存分配,原切片会受函数内赋值操作影响。