【发布时间】:2011-06-11 16:40:19
【问题描述】:
我正在阅读使用 Rails 进行敏捷 Web 开发(第 4 版),我找到了以下代码
class ApplicationController < ActionController::Base
protect_from_forgery
private
def current_cart
Cart.find(session[:cart_id])
rescue ActiveRecord::RecordNotFound
cart = Cart.create
session[:cart_id] = cart.id
cart
end
end
由于我是一名Java开发人员,我对那部分代码的理解大致如下:
private Cart currentCard(){
try{
return CartManager.get_cart_from_session(cartId)
}catch(RecordNotFoundEx e){
Cart c = CartManager.create_cart_and_add_to_session(new Cart())
return c;
}
}
让我印象深刻的是异常处理用于控制正常的应用程序流程(当用户第一次访问 Depot 应用程序时,缺少 Cart 是完全正常的行为)。
如果有人看任何 Java 书籍,他们会说这是一件非常糟糕的事情 - 并且有一个很好的理由:错误处理不应该被用来代替控制语句,这对那些阅读过的人来说是一种误导代码。
是否有充分的理由说明这种做法在 Ruby(Rails)中是合理的?这是 Ruby 中的常见做法吗?
【问题讨论】:
-
我不认为有任何特殊原因可以证明这一点,我的感觉是 Ruby 社区对“不要对控制流使用异常处理”规则存在分歧。很多人告诉你不要这样做;许多其他人无论如何都会这样做。 (有些人同意该规则,但并不总是在意;有些人认为该规则很愚蠢(或只是错误);有些人只是没有多想。)无论哪种方式,我认为您对该代码中发生的事情的感觉是正确的。如果你不喜欢它,你当然可以使用显式控制流重写它。
-
@Telemachus:这是一个很好的答案,所以发布吧!
-
@Telemachus 你的评论很有趣。我在 JRuby 中发现,构建异常回溯通常位于分析器报告的 CPU 使用率的顶部。 MRI ruby 中的基准测试显示使用异常对性能的影响不那么剧烈,但仍然可见。我的猜测是,因为异常包括回溯和其他数据,所以构建一个非常昂贵。 Ruby 还具有与救援/引发(异常)分开的 catch/throw(流控制),而且我听说 catch/throw 在 JRuby 中不是性能问题。
-
我觉得这里的用词有微妙的暗示。 “异常处理”与“错误处理”。错误是异常(希望如此),但并非每个异常都是错误。这看起来像是其中之一,exception 处理机制具有向下传播堆栈并在重要的地方得到解决的优势。
标签: ruby-on-rails ruby exception-handling