openlang

为什么递归调用期间值会改变?

怎么会这样?我该检查什么?

我的递归函数 visit(board) 接收一个结构体,在函数内部叫 incoming。

nextBoard 中有 left 和 right 两个切片。每个切片包含一些小的 cell 结构体,其成员是 label1、label2 和 bool。

visit(incoming) 里面有这些代码,

nextBoard := advance(incoming)

savedInput := incoming

visit(nextBoard)

函数内部没有其他调用 visit 的地方。

背景就是这些,问题是这样,假设 visit 在递归深度 27 被调用后,又向下走了 12 层。然后它返回深度 27。这时 incoming 的内容与调用前不同。奇怪的是 savedInput 也变了,而且和 incoming 的变化完全一样。nextBoard 仍然保持调用前的内容。

我想知道的是,这怎么可能?这 3 个变量的作用域都在函数内部,而不是包级别。

再补充一下 incoming 的变化,left 和 right 两个切片的 len 都是 7。right 切片返回后,第 7 个元素与原来不同了?

我确实知道,在深度 27 到 39 之间的某处,right 的第七个元素被替换成 left 的第七个元素,布尔值取反,同时 left 的第 7 个元素被删掉。这个修改由 advance(incoming) 函数完成。

更准确地说,incoming 返回深度 27 时,left 没有变化,而 right 有上面说的修改,也就是 right[6]=left[6] 并把布尔值取反。

我怀疑切片中的切片仍然指向与原对象共享的内存。这似乎是 incoming 和 savedInput 出现相同变化的唯一解释。但为什么调用后 incoming 会有任何变化呢?

谢谢花时间读完这些。

有什么特别需要检查的吗?我是不是误解了写下 savedInput:=incoming 的效果?我试过 :=,也试过先声明 savedInput 再用 =。

从英语翻译查看原文

后续讨论 2

顺着彼此的依据读下去

同一个问题的其他角度

  1. 同样的 sink 调用,这一行是拷贝,下一行就是移动

    Nim 2 是按调用点决定拷贝还是移动的,不是按 proc。 同一个参数,同一个 proc。第一次调用会拷贝,因为后面还要用 a。第二次就移动了。调用点上没有任何东西告诉你是哪种。nim c --expandArc:main 会打印改写后的函数体,两…

    回复 2最近活动 nim
  2. 让清理块真正执行时才开始可变借用

    怎样在 Rust 中写一个 panic 安全的机制,类似 Java 的 try { ... } finally { ... },同时允许 try 和 finally 块分别可变借用同一个值? 我需要的是,无论正常离开还是因 panic 栈展开而离开…

    回复 2最近活动 rust
  3. 通过指针输入字符数组

    每次尝试从键盘往一些 char 数组里输入内容,程序最后都会崩溃。 有什么简单方便的方法,可以从键盘读取 char 数组并保存下来?

    回复 2最近活动 c