对于正常情况而不是特殊情况使用`throw` -`catch`是不是一个坏主意?

时间:2016-02-04 02:21:31

标签: ruby exception-handling throw

我的理解是throw通常用于捕获例外情况,如下所示:

def some_callee_method
  ...
  if something_went_wrong then throw(:foo, "something wrong")
  else normal_return_value
  end
end
def some_caller_method
  e = catch(:foo) do
    ...
    some_callee_method
    ...
  end
  raise some_processed_error if e == "something wrong"
  ... # Unthrown. Continue normal cases
end

但是在上面的用法中,throw的返回值和some_callee_method的正常返回值在收到catch块的返回值时会混淆(e以上),因此需要在catch块之后进行调节才能将其分开。

我觉得这很麻烦,并且在某些情况下,如果可能的话,我虽然在正常情况下反转它:throw而不是如下的特殊情况。 (在这种情况下,只有some_callee_method的最后一步才能出错,或者即使出现问题也可以继续到some_callee_method的末尾。)

def some_callee_method
  ...
  throw(:foo, normal_return_value) unless something_went_wrong
end
def some_caller_method
  e = catch(:foo) do
    ...
    some_callee_method
    raise some_processed_error
  end
  ... # Thrown. Continue normal cases
end

我关注的是使用throw - catch的效率。在第一种情况下,throw用于表示异常情况,每个程序执行时最多只发生一次,并且是用户应该努力避免的情况,因此性能不是一个大问题。但是,在第二种情况下,正常情况下会发生大量throw - catch。在性能方面,采用第二种形式是一个坏主意吗?

或者更常见的是,频繁使用throw - catch会对效果产生负面影响吗?

有时候应该避免在正常情况下使用rescue来捕获异常,因为它会对性能产生负面影响。例如,要检查字符串是否表示整数,下面的第二个表单优先于第一个表单(我想这不仅仅是因为它的优雅)。

def is_int?(string)
  Integer(string)
  true
rescue ArgumentError
  false
end

def is_int?(string)
  not string.empty? and string !~ /\D/
end

我想知道throw - catch是否相同。

2 个答案:

答案 0 :(得分:1)

TL; DR

我不相信throw / catch通常是方法之间适当的流量控制机制,尽管如果你足够努力,可以以这种方式使用它。 throw / catch的真实用例是用于处理嵌套循环。请参阅下面的更长解释。

Catch / Throw用于嵌套循环

throw和catch的主要用例是退出深层嵌套的流控制结构。来自Programming Ruby

  

虽然提升和救援的异常机制非常适合在出现问题时放弃执行,但在正常处理期间能够跳出一些深度嵌套的构造有时会很好。这就是捕捉和投掷派上用场的地方。

虽然他们在本书中给出了一些例子,但您可能会考虑更复杂的案例,如:

catch :done do
  while true do
    while true do
      while true do
        while true do
          nested_levels = 4
          puts "levels: #{nested_levels}"
          throw :done, nested_levels
        end
      end
    end
  end
end
#=> 4

如果您只用一个throw替换break,那么您仍会永远保持循环。现在考虑明确地突破所有包含循环所需的break个关键字和条件。 throw / catch组合允许您从任意深度循环中解除,并且对于您不希望从方法return或引发异常只是为了退出这组循环的情况非常方便

答案 1 :(得分:0)

当目标是浏览某个集合直到找到一个对象并立即返回它时,

WM_QUERYENDSESSION才有意义。中间状态并不重要:唯一真正重要的是搜索对象。

十个朋友去看足球比赛。其中一个有所有门票。他们在体育场入口外排队。门票收件人要求排队的第一个人出票,但他没有票。

他问下一个人排队。他也没有门票。每个人都要求下一个人排队买票。最终,找到了门票。

现在,在这一点上,许多程序员会坚持认为带票的人应该把他们交给他面前的那个人,他会把他们交给等人。 ,直到他们到达前线的那个人。但相反,拿着门票的人只能喊出来#34;我有门票!"并把它们交给买票人。这就是throw/catch的工作方式。