在大多数其他语言中,catch和throw语句执行begin,rescue和raise语句在Ruby中执行的操作。我知道你可以用这两个陈述来做到这一点:
catch :done do
puts "I'm done."
end
和
if some_condition
throw :done
end
但这有用吗?有人可以给我一个关于Ruby中使用catch和throw语句的例子吗?
答案 0 :(得分:34)
您可以使用它来打破嵌套循环。
INFINITY = 1.0 / 0.0
catch (:done) do
1.upto(INFINITY) do |i|
1.upto(INFINITY) do |j|
if some_condition
throw :done
end
end
end
end
如果您使用了上面的break语句,那么它就会破坏内部循环。但是如果你想要打破嵌套循环,那么这个catch / throw会非常有用。我用here来解决欧拉问题之一。
答案 1 :(得分:21)
我一直在寻找一个很好的例子,直到我遇到Sinatra。
恕我直言,Sinatra为catch
公开了一个非常有趣的示例用法。
在Sinatra,您可以halt
随时使用halt
。
halt 410
您还可以在暂停时指定状态...
halt 'this will be the body'
或身体......
halt 401, 'go away!'
或两者......
def halt(*response)
response = response.first if response.length == 1
throw :halt, response
end
暂停方法为immediately terminate a request。
invoke
和implemented using throw :halt
方法。
Sinatra中有{{1}}的几种用法。您可以阅读源代码以获取更多示例。
答案 2 :(得分:1)
在编写使用递归函数作用于嵌套数据结构的递归算法时,您可以使用throw
类似于在编写行为的迭代算法时使用break
或早期return
的方式使用for
循环对平面数据进行处理。
例如,假设您有一个正整数列表,并且您希望(出于某种原因)编写一个函数,如果满足以下任一条件,该函数将返回true:
让我们说你总是希望在列表中的单个短路传递中执行此检查,而不是进行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中,有!假设,有一个树而不是拥有一个列表并且想要检查其元素是否包含五个或总和超过100,并且想要检查它的离开是否包含一旦你知道答案就会发生五次或者一次超过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
电话下面的整个调用堆栈。在其他语言中,您可以通过为此目的滥用异常或使用一些返回代码来告诉递归函数停止递归来实现此目的,但这更直接,更简单。