我和我的朋友们正在做一些基本的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
下面是Node类:
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
我们期望测试的最后一行会导致无限递归,直到堆栈溢出,因为它应该不断地将子节点相互比较,并且永远不会找到叶节点。(我们的印象是,数组上的==
操作符将迭代数组,并根据RubyDoc的数组页面在每个子元素上调用==
。)但是如果我们将puts
扔到==
方法中,看看它被调用的频率,我们发现它被调用了三次,然后测试通过。
我们遗漏了什么
编辑:注意,如果将测试中的be_false
替换为be_true
,则测试失败。所以它肯定认为数组是不相等的,它只是没有递归它们(除了对==
的三个不同调用)。
1条答案
按热度按时间o75abkj41#
如果你点击你链接的RubyDoc的方法名,你会看到
Array#==
方法的源代码(C):这个实现(特别是“recursive_equal”)表明
Array#==
已经实现了您所追求的无限递归保护。