关于go里切片作为函数参数时是引用传递还是值传递

问题起因

写一道回溯算法题,把ans二维数组作为函数参数传入,想在函数里面,不停地append,最后返回ans
实际发现ans打印出来是空的,就很奇怪,因为我是事先分配好空间的,理论上不会发生扩容,底层数组是共用的,咋回事

func permute(nums []int) [][]int {
    ans := make([][]int, 0, len(nums)*len(nums))
    item := append([]int{}, nums...)
    backtracking(0, item, nums,&ans)
    return ans
}

func backtracking(i int, cur, nums []int, ans [][]int) {
    if i == len(nums) {
        tmp := slices.Clone(cur)
        ans = append(ans, tmp)
        return
    }
    for j:=i;j<len(nums);j++ {
        swap(i, j, cur)
        backtracking(i+1, cur, nums, ans)
        swap(i, j, cur)
    }
}

func swap(i,j int, nums []int) {
    nums[i], nums[j] = nums[j], nums[i]
}

传递指针问题解决

*ans [][]int

分析原因

切片里不止有底层数组啊,还有Len Cap这些基础数据类型;修改是不可见的
在Go语言中,切片(slice)作为函数参数传递时,是通过值传递的,但这里传递的值是切片头(slice header),其中包含指向底层数组的指针、长度和容量。这意味着函数内部可以通过这个指针修改底层数组的元素,但如果对切片进行追加(append)操作,可能会改变切片头的值(例如长度和指针),这些更改不会反映到外部切片中,因为函数内部操作的是切片头的副本。

import "slices"

func permute(nums []int) [][]int {
    ans := make([][]int, 0)
    n := len(nums)
    // 创建当前排列的副本,用于回溯操作
    cur := make([]int, n)
    copy(cur, nums)
    
    // 定义闭包函数
    var backtrack func(int)
    backtrack = func(i int) {
        if i == n {
            // 将当前排列添加到答案中
            tmp := slices.Clone(cur)
            ans = append(ans, tmp)
            return
        }
        for j := i; j < n; j++ {
            // 交换元素
            cur[i], cur[j] = cur[j], cur[i]
            backtrack(i + 1)
            // 回溯,恢复交换
            cur[i], cur[j] = cur[j], cur[i]
        }
    }
    backtrack(0)
    return ans
}

参考,最下面评论区

posted @ 2025-09-15 23:08  柠檬水请加冰  阅读(8)  评论(0)    收藏  举报