代码之家  ›  专栏  ›  技术社区  ›  David

为什么这个递归不是无限的?

  •  9
  • David  · 技术社区  · 14 年前

    我和我的朋友们正在做一些基本的Ruby练习来了解Ruby语言,我们遇到了一个有趣的行为,但我们还不能理解。基本上,我们正在创造一个 tree node ,它只包含一个值和一个零或多个值的数组 nodes . 我们正在使用 rspec 的autospec测试运行程序。有一次我们开始编写测试来禁止无限递归(一种循环树结构)。

    下面是我们的测试:

    it "breaks on a circular reference, which we will fix later" do
      tree1 = Node.new 1
      tree2 = Node.new 1
      tree2.add_child tree1
      tree1.add_child tree2
      (tree1 == tree2).should be_false
    end
    

    下面是节点类:

    class Node
      attr_accessor :value
      attr_reader :nodes
    
      def initialize initial_value = nil
        @value = initial_value
        @nodes = []
      end
    
      def add_child child
        @nodes.push child
        @nodes.sort! { |node1, node2| node1.value <=> node2.value }
      end
    
      def == node
        return (@value == node.value) && (@nodes == node.nodes)
      end
    end
    

    我们期望测试的最后一行会导致无限递归,直到堆栈溢出,因为它应该不断地将子节点相互比较,并且永远找不到叶节点。(我们的印象是 == 数组上的运算符将遍历数组并调用 在每个孩子身上,基于 the array page of RubyDoc puts 进入 == 方法来查看它被调用的频率,我们发现它正好被调用了三次,然后测试就通过了。

    我们错过了什么?

    编辑 be_false 在测试中 be_true 然后测试失败。所以它肯定认为数组是不相等的,只是没有在它们上面递归(除了对 ==

    1 回复  |  直到 14 年前
        1
  •  7
  •   Gareth    14 年前

    Array#== 方法:

    {
        // [...]
        if (RARRAY(ary1)->len != RARRAY(ary2)->len) return Qfalse;
        if (rb_inspecting_p(ary1)) return Qfalse;
        return rb_protect_inspect(recursive_equal, ary1, ary2);
    }
    

    这个实现(特别是“递归的∗equal”)表明 数组#==