为了账号安全,请及时绑定邮箱和手机立即绑定

go slice 的行为不符合预期

go slice 的行为不符合预期

Go
蓝山帝景 2023-08-14 14:31:22
我试图亲自动手切片,但我发现它的行为不符合预期。我试图获得 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]]
查看完整描述

1 回答

?
幕布斯7119047

TA贡献1794条经验 获得超8个赞

这是因为append工作原理。在 Go 中,slice 是一个包含 3 个属性的标头:LenCap、 和PtrLen是切片本身的长度,Cap是切片底层数组(内存)的容量,Ptr是指向数组的指针。

append追加到基础数组中没有更多空间的切片时,它会分配一个比所需空间多的新基础数组,并将原始切片的内容复制到其中,然后添加新元素。

append附加到切片时,其中CapLen,即已分配的内存中仍然有足够的空间,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


查看完整回答
反对 回复 2023-08-14
  • 1 回答
  • 0 关注
  • 101 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信