繁体   English   中英

将指针传递给go中的切片时发生意外行为

[英]Unexpected behavior when passing a pointer to a slice in go

下面的go程序应该生成整数切片的所有排列:

package main
import "fmt"

func permute(nums []int) [][]int {
    var res [][]int
    var s []int
    permuteHlp(&res, nums, 0, s)
    return res
}

func permuteHlp(res *[][]int, nums []int, i int, s []int) {
    if i == len(nums) {
        *res = append(*res, s)
        return
    }

    for j := i; j < len(nums); j++ {
        s = append(s, nums[j])
        nums[i], nums[j] = nums[j], nums[i]
        permuteHlp(res, nums, i+1, s)
        s = s[:len(s)-1]
        nums[i], nums[j] = nums[j], nums[i]
    }
}

func main() {
    x := []int{1,2,3,4}
    y := permute(x)

    fmt.Println(y)
}

输出意外

[[1 2 4 3] [1 2 4 3] [1 3 4 2] [1 3 4 2] [1 4 2 3] [1 4 2 3] [2 1 4 3] [2 1 4 3] [2 3 4 1] [2 3 4 1] [2 4 1 3] [2 4 1 3] [3 2 4 1] [3 2 4 1] [3 1 4 2] [3 1 4 2] [3 4 2 1] [3 4 2 1] [4 2 1 3] [4 2 1 3] [4 3 1 2] [4 3 1 2] [4 1 2 3] [4 1 2 3]]

我不明白这里出了什么问题。 我将不胜感激任何帮助。 谢谢!

您正在传递指向同一切片的指针。 最后,您在结果中使用了一系列指向同一切片的指针,因此,当然所有值都将是相同的-它是一遍又一遍打印的同一切片。

还值得注意的是,指向切片的指针很少是您想要的,因为切片已包含指向基础数组的指针。

切片本身就是指针,因此无需指向切片的指针。 “切片是对数组连续段的引用 。”, 参考

您看到的奇怪行为是因为您使用的是追加,当切片超出其容量时,需要创建容量增加的新切片并复制原始切片的所有内容(这是追加在后台执行的操作),因此新切片将不再指向原始基础数组。

建议不要将切片作为函数的返回值而不是修改传入的参数。

func permute(nums []int) [][]int {
   res := permuteHlp(nums, 0, new([]int))
   return res
}

我建议您阅读golang.org中有关切片内部的博客文章, 在这里


编辑:

我添加了一个重构,从这个答案中提取了算法。

package main

import (
    "fmt"  
)

func permutations(arr []int)[][]int{
    var helper func([]int, int)
    res := [][]int{}

    helper = func(arr []int, n int){
        if n == 1{
            tmp := make([]int, len(arr))
            copy(tmp, arr)
            res = append(res, tmp)
        } else {
            for i := 0; i < n; i++{
                helper(arr, n - 1)
                if n % 2 == 1{
                    tmp := arr[i]
                    arr[i] = arr[n - 1]
                    arr[n - 1] = tmp
                } else {
                    tmp := arr[0]
                    arr[0] = arr[n - 1]
                    arr[n - 1] = tmp
                }
            }
        }
    }
    helper(arr, len(arr))
    return res
}

func main() {
    x := []int{1,2,3,4}
    d := permutations(x)
    fmt.Print(d)
}

通常,您不希望有指向切片的指针,而是从该函数返回一个新的切片,然后再对另一件事进行注释,并尽可能不使用递归,因为golang没有尾调用优化及其循环表现出色。 希望能帮助到你!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM