如何理解golang slice的以下代码?

时间:2018-01-28 13:50:38

标签: go copy slice

最近我发现了一些我无法理解的代码,下面是我的代码:

func subsetsWithDup(nums []int) [][]int {
    if len(nums) == 0 {
        return [][]int{[]int{}}
    }
    sort.Ints(nums)
    result := [][]int{}
    backtracking(nums, &result, []int{}, 0)
    return result
}

func backtracking(nums []int, result *[][]int, tempList []int, start int) {
    *result = append(*result, tempList)
    for i := start; i < len(nums); i++ {
        if i > start && nums[i] == nums[i-1] {
            continue
        }
        tempList = append(tempList, nums[i])
        backtracking(nums, result, tempList, i+1)
        tempList = tempList[:len(tempList)-1:len(tempList)-1]
    }
}

和另一种方法:

func subsetsWithDup(nums []int) [][]int {
    sort.Ints(nums)
    return subsets(nums, []int{}, [][]int{})
}

func subsets(nums []int, result []int, results [][]int) [][]int {    
    newR := make([]int, len(result))
    copy(newR, result)
    results = append(results, newR)

    if len(nums) == 0 {return results}

    for i := 0; i < len(nums); i++ {
        if i > 0 && nums[i] == nums[i - 1] {continue}
        result = append(result, nums[i])
        results = subsets(nums[i + 1:], result, results)
        result = result[:len(result) - 1]
    }

    return results
}

在第一种方法中,我使用以下代码:

tempList = tempList[:len(tempList)-1:len(tempList)-1]

它有效,但如果我将其更改为:

tempList = tempList[:len(tempList)-1]

它不起作用。在第二种使用复制功能的方法也有效。我想知道代码背后会发生什么,感谢任何帮助,谢谢。

1 个答案:

答案 0 :(得分:1)

在Go中,slice是一种指针类型,用于维护有关底层数组的信息,因此更改底层数组会导致切片值发生变化,这有时可能会令人惊讶。

谜题的第二部分是append如果cap的{​​{1}}足够,则会修改基础数组。文件:

  

追加内置函数将元素附加到切片的末尾。   如果它具有足够的容量,则目标将被复制到   适应新元素。如果没有,则为新的底层数组   将被分配。 Append返回更新的切片。因此   必须存储追加的结果,通常在变量持有中   切片本身。

因此,在尝试失败时,slice可能会更改tempList = append(tempList, nums[i])中先前存储的切片的值。

另一方面,第二种方法创建一个带有新底层数组的新切片并明确地复制到它,因此避免了错误。第一种方法更精细,因为它使用完整切片表达式result。代码限制了新切片的tempList[:len(tempList)-1:len(tempList)-1],因此cap每次都必须分配一个新的底层数组,而不是使用orignal数组。

有关完整切片表达式(规范)的更多信息:

  

对于数组,指向数组的指针,或切片a(但不是字符串),主表达式

append
  

构造一个相同类型的切片,并且具有与简单切片表达式相同的长度和元素a [low:high]。此外,它通过将切片的容量设置为max - low来控制切片的容量。只能省略第一个索引;它默认为0.切片后的数组

a[low : high : max]
  

切片t的类型为[] int,长度为2,容量为4,元素为

a := [5]int{1, 2, 3, 4, 5}
t := a[1:3:5]