在使用递归函数编写作用于嵌套数据结构的递归算法时,您可以使用throw,类似于使用@987654324 编写作用于平面数据的迭代算法时使用break 或早期return @循环。
例如,假设您有一个正整数列表,并且您希望(出于某种原因)编写一个函数,如果满足以下任一条件,该函数将返回 true:
- 列表中所有元素之和大于100
- 列表中的某个元素如果等于 5
我们还假设您总是希望在一个单一的、短路的遍历列表中执行此检查,而不是执行reduce 调用来获取总和并单独调用any? 来查找五分之二。
你可能会写一些有点像这样的代码(事实上,你可能在你生命中的某个时刻用某种语言写过这样的代码):
def test(list)
sum = 0
for i in list
sum += i
if i == 5 || sum > 100
return true
end
end
return false
end
在大多数语言中,没有明确的等价物可以打破使用递归函数的递归算法。但是,在 Ruby 中,有!假设您有一个 tree 并想要检查其 叶子 是否包含5 或总和超过 100,同时短路并在您知道答案后立即返回。
你可以用throw/catch优雅地做到这一点,像这样:
def _test_recurse(sum_so_far, node)
if node.is_a? InternalNode
for child_node in node.children
sum_so_far = _test_recurse(sum_so_far, child_node)
end
return sum_so_far
else # node.is_a? Leaf
sum_so_far += node.value
if node.value == 5
throw :passes_test
elsif sum_so_far > 100
throw :passes_test
else
return sum_so_far
end
end
end
def test(tree)
catch (:passes_test) do
_test_recurse(0, tree)
return false
end
return true
end
这里的throw :passes_test 有点像break;它使您可以跳出最外面的_test 调用下方的整个调用堆栈。在其他语言中,您可以通过为此目的滥用异常或使用一些返回码来告诉递归函数停止递归来做到这一点,但这更直接和更简单。