MST

星途 面试题库

面试题:Go数组在函数传递中的行为与优化

在Go语言中,当把数组作为参数传递给函数时,会发生什么?请分析这种传递方式可能带来的性能问题,特别是在数组较大的情况下。并提出至少两种优化方案来提高性能,同时说明每种方案的优缺点。
42.3万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
  1. 数组作为参数传递时的情况: 在Go语言中,当数组作为参数传递给函数时,是值传递。这意味着函数接收的是原数组的一个副本,对副本的任何修改都不会影响原数组。例如:
    package main
    
    import "fmt"
    
    func modifyArray(arr [3]int) {
        arr[0] = 100
    }
    
    func main() {
        original := [3]int{1, 2, 3}
        modifyArray(original)
        fmt.Println(original)
    }
    
    上述代码中,modifyArray函数修改的是original数组的副本,original数组本身不会改变,输出仍然是[1 2 3]
  2. 性能问题: 当数组较大时,值传递会导致大量的数据复制,这会消耗额外的内存和时间。比如有一个非常大的数组[1000000]int,传递给函数时,函数内部会复制一份1000000个int大小的数据,这对内存和性能都是很大的开销。
  3. 优化方案
    • 使用数组指针
      • 优点:避免了数组的整体复制,只传递一个指针,大大减少了内存开销和传递时间。例如:
        package main
        
        import "fmt"
        
        func modifyArrayPtr(arr *[3]int) {
            (*arr)[0] = 100
        }
        
        func main() {
            original := [3]int{1, 2, 3}
            modifyArrayPtr(&original)
            fmt.Println(original)
        }
        
        上述代码中,modifyArrayPtr函数接收的是数组指针,对指针指向的数组进行修改,original数组也会改变,输出为[100 2 3]
      • 缺点:函数调用者需要注意传递指针,代码可读性可能会略有下降,并且指针操作相对复杂一些,如果使用不当可能会导致空指针异常等问题。
    • 使用切片
      • 优点:切片本质上是一个轻量级的数据结构,包含一个指向底层数组的指针、长度和容量。传递切片时只是复制了切片头(通常是3个机器字长,在64位系统上为24字节),而不是整个底层数组。例如:
        package main
        
        import "fmt"
        
        func modifySlice(slice []int) {
            slice[0] = 100
        }
        
        func main() {
            original := []int{1, 2, 3}
            modifySlice(original)
            fmt.Println(original)
        }
        
        上述代码中,modifySlice函数接收切片并修改,original切片也会改变,输出为[100 2 3]。切片在Go语言中使用非常灵活,易于理解和操作。
      • 缺点:由于切片共享底层数组,如果不小心在多个地方通过切片修改底层数组,可能会出现意想不到的结果,增加调试难度。同时,切片的扩容机制也需要开发者注意,不合理的扩容可能会导致额外的性能开销。