MST

星途 面试题库

面试题:Go语言切片参数传递与内存分配

假设有一个函数`func modifySlice(s []int)`,在函数内部对`[]int`类型的切片` s`进行扩容操作后再赋值,这会对调用该函数时传入的原切片产生怎样的影响?从内存分配和切片结构角度进行分析。
41.9万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
  1. 切片结构
    • 在Go语言中,切片是一个包含三个字段的结构体:指向底层数组的指针、切片的长度(len)和切片的容量(cap)。
    • 例如,对于切片s := []int{1, 2, 3},它有一个指向包含[1, 2, 3]的底层数组的指针,长度len(s)=3,容量cap(s)一般初始化为3(如果没有后续操作扩容,这里假设是3)。
  2. 内存分配
    • 当调用func modifySlice(s []int)函数并在函数内部进行扩容操作时:
      • 如果当前切片的容量不足以容纳新的元素,Go语言会重新分配内存。它会分配一个更大的底层数组,然后将原底层数组的内容复制到新的底层数组中。
      • 例如,原切片s容量为3,现在要增加到4个元素,就需要重新分配内存。新的底层数组大小可能是原容量的2倍(不同版本的Go语言扩容策略可能有差异,一般是2倍),即新容量为6,然后将原数组[1, 2, 3]复制到新数组的前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]

综上所述,若函数内部扩容导致新内存分配,原切片不受影响;若未导致新内存分配,原切片会受函数内赋值操作影响。