go slice 的行为不符合预期

我试图亲自动手切片,但我发现它的行为不符合预期。


我试图获得 n 个不同大小的数组的笛卡尔积。输出不正确。


这是我的代码



func main() {

   sl1 := []int{1,2,3}

   sl2 := []int{4}

   sl3 := []int{5,6}

   sl4 := []int{8,9}

   sl := [][]int{sl1,sl2,sl3,sl4}

   res := cartesianMain(sl)

   fmt.Println(res)

}


func cartesianMain(a [][]int)  [][]int {

   res := [][]int{}

   for i:=0;i<len(a[0]) ;i++{

       res = append(res,[]int{a[0][i]})

   }

   for i:= 1;i<len(a) ;i++{

       res = cartesianProduct(res,a[i])

   }

   return res;

}

func cartesianProduct(a [][]int, b []int) [][]int {

   result := [][]int{}

   for _,v1 := range b {

       for _,v2 := range a {

           result = append(result, append(v2,v1))

       }

   }

return result

}

实际输出:


[[1 4 5 9] [2 4 5 9] [3 4 5 9] [1 4 6 9] [2 4 6 9] [3 4 6 9] [1 4 5 9] [2 4 5 9] [3 4 5 9] [1 4 6 9] [2 4 6 9] [3 4 6 9]]

预期输出:如果您看到 sl4 的第一个元素 8 被 9 覆盖。正确答案是:


[[1 4 5 8] [2 4 5 8] [3 4 5 8] [1 4 6 8] [2 4 6 8] [3 4 6 8] [1 4 5 9] [2 4 5 9] [3 4 5 9] [1 4 6 9] [2 4 6 9] [3 4 6 9]]



蓝山帝景
浏览 70回答 1
1回答

幕布斯7119047

这是因为append工作原理。在 Go 中,slice 是一个包含 3 个属性的标头:Len、Cap、 和Ptr。Len是切片本身的长度,Cap是切片底层数组(内存)的容量,Ptr是指向数组的指针。当append追加到基础数组中没有更多空间的切片时,它会分配一个比所需空间多的新基础数组,并将原始切片的内容复制到其中,然后添加新元素。当append附加到切片时,其中Cap> Len,即已分配的内存中仍然有足够的空间,append保留底层数组并复制要添加到的元素a[Len+1](其中 a 是底层数组)。当两个或多个切片共享底层内存时,这将导致问题。经验法则是经常检查复制切片的需要,以避免不必要的底层数组共享。要解决该问题,请更改result = append(result, append(v2,v1))为result = append(result, append([]int{}, append(v2, v1)...)).注1:是和append([]int{},append(v2,v1...))的快捷方式。注2:在Go中,nil是slice的有效值。cartesianMain所以你可以通过设置来res摆脱split in 的分离[]int{nil}。注 3:为了获得更好的性能和更少的分配,最好为已知切片设置容量(或长度)。在 中cartesianProduct,您可以使用result := make([][]int, 0, len(a)*len(b)).游乐场:https://play.golang.org/p/rLqDGWoTLKS
打开App,查看更多内容
随时随地看视频慕课网APP