V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
liaowb3
V2EX  ›  Go 编程语言

我发现 go 好像有个 bug

  •  
  •   liaowb3 · 147 天前 · 3490 次点击
    这是一个创建于 147 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我先上代码

    
    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 这是为什么呢?

    14 条回复    2024-08-23 19:21:47 +08:00
    sagaxu
        1
    sagaxu  
       147 天前
    猜谜语啦,OP 代码的意图是什么?
    zzhaolei
        2
    zzhaolei  
       147 天前
    这就是 go 的 bug 了?有没有简化的最小复现版?
    kingcanfish
        3
    kingcanfish  
       147 天前
    为啥不先怀疑自己有没有语法错误或者解法错误,而怀疑是 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)
    }
    ```
    LittleYangYang
        4
    LittleYangYang  
       147 天前
    不明白 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)
    Kinnice
        5
    Kinnice  
       147 天前 via Android   ❤️ 9
    放心,粗看了一下代码,你的技术水平还不至于可以发现 go 的 bug.
    husher123
        6
    husher123  
       147 天前
    回答这种问题应该 gpt 很擅长呀~

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

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

    以下是修改后的代码:

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

    通过使用 make 和 copy 函数,我们创建了一个新的切片 newAns ,从而避免了对同一底层数组的引用。这将解决你所遇到的问题。
    cmdOptionKana
        7
    cmdOptionKana  
       147 天前
    OP 是担心不这样问就没人回答问题?
    SmartLeo
        8
    SmartLeo  
       147 天前
    ```
    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.Printf("t: ans:%p new:%p\n", ans, new)
    fmt.Printf("t: Cap(ans):%d Cap(new):%d\n", cap(ans), cap(new))
    fmt.Printf("t: L(ans):%d L(new):%d\n", len(ans), len(new))
    fmt.Println(root.Val, ":")
    if root.Right != nil {
    fmt.Printf("%d %v %p\n", root.Right.Val, right, right)
    }
    if root.Left != nil {
    fmt.Printf("%d %v %p\n", root.Left.Val, left, left)
    }

    result := right
    if len(left) > len(right) {
    result = append(result, left[len(right):]...)
    }
    fmt.Println()
    fmt.Println(result)
    fmt.Printf("t: result:%p\n\n", result)
    return result
    }
    ```
    肯定不是 go 的问题啦,是你代码逻辑问题。
    你没有完整地了解 slice 的一些特性。

    你可以用这段代码看看。

    具体到你的问题,显然到 3 那个节点的时候,左右的 slice 是同一个 slice ,而这个 slice 因为调用关系,被最后 left 的处理逻辑最后覆写了。
    deplives
        9
    deplives  
       147 天前 via iPhone   ❤️ 1
    众所周知,自认为发现主流语言 bug 的都是_____



    学艺不精(俗称菜狗)
    PTLin
        10
    PTLin  
       147 天前
    go 虽然很简单,但是还没简单到学一天就能让你了解到所有 go 的小坑。
    dingawm
        11
    dingawm  
       146 天前   ❤️ 1
    错误的提问:求大家帮忙看看我的代码有啥问题
    正确的提问:我发现 go 好像有个 bug
    开个玩笑,楼主也许真的以为是 bug
    honjow
        12
    honjow  
       146 天前 via iPhone   ❤️ 1
    在 v2 看到好几个刚学习就嚷嚷发现语言 bug 的帖子了。结果都是自己没搞清楚,大多都是引用相关问题
    guanzhangzhang
        13
    guanzhangzhang  
       146 天前
    上次监听 ipv6 地址报错参数错误,我怀疑 golang 的 bug ,然后 dlv 调试下发现错误是_syscall 调用系统返回的,然后用 python 写了个大概逻辑也是一样的报错,最后才发现是内核返回的 ,怀疑有 bug 不应该自己调试下吗
    xiaozirun
        14
    xiaozirun  
       127 天前
    怀疑题主是想找人帮他找出他写的 bug🤣
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2560 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 03:02 · PVG 11:02 · LAX 19:02 · JFK 22:02
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.