Golang Go语言中我发现好像有个bug

发布于 1周前 作者 eggper 来自 Go语言

我先上代码


type TreeNode struct {
	Val   int
	Left  *TreeNode
	Right *TreeNode
}

func Solution199(root *TreeNode) []int { return dfs199(root, []int{}) }

func dfs199(root *TreeNode,ans []int)[]int{ if root == nil{ return ans } new := append(ans,root.Val)

right := dfs199(root.Right,new)

left := dfs199(root.Left,new)


fmt.Println(root.Val,":")
if root.Right != nil{
	fmt.Println(root.Right.Val,right)
}
if root.Left != nil{
	fmt.Println(root.Left.Val,left)
}



result := right
if len(left) > len(right){
	result = append(result,left[len(right):]...)
}
fmt.Println(result)
return result

}

func main() { root := &tree.TreeNode{ Val: 1, Left: nil, Right: &tree.TreeNode{ Val: 5, Left: &tree.TreeNode{ Val: 3, Left: &tree.TreeNode{ Val: 2, Left: nil, Right: nil, }, Right: &tree.TreeNode{ Val: 4, Left: nil, Right: nil, }, }, Right: nil, }, } fmt.Println(tree.Solution199(root)) }

我发现 当递归到 3 这个节点的时候,right 这个数组 通过 dfs199 函数递归后得到是 1534 ,但是当下一个 left 这个数组 通过 dfs199 函数递归后得到 1532 的时候,right 也会跟着变成 1532 这是为什么呢?


Golang Go语言中我发现好像有个bug

更多关于Golang Go语言中我发现好像有个bug的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

15 回复

猜谜语啦,OP 代码的意图是什么?

更多关于Golang Go语言中我发现好像有个bug的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这就是 go 的 bug 了?有没有简化的最小复现版?

为啥不先怀疑自己有没有语法错误或者解法错误,而怀疑是 go 有 bug
还有你这二叉树右视图解法不对吧
````
func rightSideView(root *TreeNode) []int {
var ans []int
dfs(root, 0, &ans)
return ans
}


func dfs(root *TreeNode, level int, ans *[]int) {
if root == nil {
return
}

if level == len(*ans) {
*ans = append(*ans, root.Val)
}
dfs199(root.Right, level+1, ans)
dfs199(root.Left, level+1, ans)
}
```

不明白 OP 是什么意图,但盲猜一个是 Slice 底层数组共享了

参考

func Test(t *testing.T) {
base := []int{1, 2, 3}
base1 := append(base, 4)
base2 := append(base1, 5)

fmt.Println(“Before:”)
fmt.Println(base)
fmt.Println(base1)
fmt.Println(base2)

base1[0] = 0
base2[1] = 0

fmt.Println(“After:”)
fmt.Println(base)
fmt.Println(base1)
fmt.Println(base2)
}

=== RUN Test
Before:
[1 2 3]
[1 2 3 4]
[1 2 3 4 5]
After:
[1 2 3]
[0 0 3 4]
[0 0 3 4 5]
— PASS: Test (0.00s)

放心,粗看了一下代码,你的技术水平还不至于可以发现 go 的 bug.

回答这种问题应该 gpt 很擅长呀~

你遇到的问题是由于 Go 中的切片 (slice) 的底层实现导致的。切片是指向底层数组的引用,因此在函数中对切片的修改会影响到其他引用该切片的变量。具体来说,当你在递归函数中对 right 进行递归调用时,right 和 new 共享同一个底层数组。于是当 left 再次使用 new 时,会改变同一个底层数组,导致 right 的值也被修改。

为了避免这个问题,可以在递归调用前创建新的切片,这样 right 和 left 就不会共享同一个底层数组。

以下是修改后的代码:

https://go.dev/play/p/pHLut5kz-uu

通过使用 make 和 copy 函数,我们创建了一个新的切片 newAns ,从而避免了对同一底层数组的引用。这将解决你所遇到的问题。

OP 是担心不这样问就没人回答问题?

<br>func dfs199(root *TreeNode, ans []int) []int {<br> if root == nil {<br> return ans<br> }<br> new := append(ans, root.Val)<br><br> right := dfs199(root.Right, new)<br><br> left := dfs199(root.Left, new)<br><br> fmt.Printf("t: ans:%p new:%p\n", ans, new)<br> fmt.Printf("t: Cap(ans):%d Cap(new):%d\n", cap(ans), cap(new))<br> fmt.Printf("t: L(ans):%d L(new):%d\n", len(ans), len(new))<br> fmt.Println(root.Val, ":")<br> if root.Right != nil {<br> fmt.Printf("%d %v %p\n", root.Right.Val, right, right)<br> }<br> if root.Left != nil {<br> fmt.Printf("%d %v %p\n", root.Left.Val, left, left)<br> }<br><br> result := right<br> if len(left) &gt; len(right) {<br> result = append(result, left[len(right):]...)<br> }<br> fmt.Println()<br> fmt.Println(result)<br> fmt.Printf("t: result:%p\n\n", result)<br> return result<br>}<br>
肯定不是 go 的问题啦,是你代码逻辑问题。
你没有完整地了解 slice 的一些特性。

你可以用这段代码看看。

具体到你的问题,显然到 3 那个节点的时候,左右的 slice 是同一个 slice ,而这个 slice 因为调用关系,被最后 left 的处理逻辑最后覆写了。

众所周知,自认为发现主流语言 bug 的都是_____



学艺不精(俗称菜狗)

go 虽然很简单,但是还没简单到学一天就能让你了解到所有 go 的小坑。

错误的提问:求大家帮忙看看我的代码有啥问题
正确的提问:我发现 go 好像有个 bug
开个玩笑,楼主也许真的以为是 bug

在 v2 看到好几个刚学习就嚷嚷发现语言 bug 的帖子了。结果都是自己没搞清楚,大多都是引用相关问题

上次监听 ipv6 地址报错参数错误,我怀疑 golang 的 bug ,然后 dlv 调试下发现错误是_syscall 调用系统返回的,然后用 python 写了个大概逻辑也是一样的报错,最后才发现是内核返回的 ,怀疑有 bug 不应该自己调试下吗

怀疑题主是想找人帮他找出他写的 bug🤣

在Golang(Go语言)中遇到看似bug的问题时,首先需要确保我们对问题的理解是准确的,并且已经进行了必要的排查步骤。以下是一些建议,帮助你更有效地定位和解决这个问题:

  1. 查阅文档和社区

    • 确保你正在使用的Go版本是最新的,或者至少是官方支持的稳定版本。
    • 查阅Go语言的官方文档,特别是与你遇到问题相关的部分。
    • 搜索Go语言的相关社区和论坛,看看是否有其他人遇到过类似的问题。
  2. 编写和运行测试用例

    • 尝试编写一个小的、独立的测试用例,以复现你遇到的问题。
    • 逐步简化代码,直到你能确定导致问题的最小代码片段。
  3. 使用调试工具

    • 使用Go语言的调试工具(如Delve)来逐步执行代码,观察变量的值和程序的执行路径。
    • 检查是否有内存泄漏、数据竞争或其他并发问题。
  4. 检查第三方库

    • 如果你在使用第三方库,确保它们是兼容你当前Go版本的,并且没有已知的bug。
    • 尝试更新或替换这些库,看看问题是否仍然存在。
  5. 报告和寻求帮助

    • 如果经过上述步骤后仍然无法解决问题,可以考虑向Go语言的官方GitHub仓库提交一个issue。
    • 在提交issue之前,确保你已经阅读了项目的贡献指南,并提供了足够的信息来复现问题。

希望这些建议能帮助你解决在Go语言中遇到的问题!

回到顶部