【问题标题】:Are `return` and `break` useless inside a Ruby block when used as a callback?当用作回调时,Ruby 块中的“return”和“break”是否无用?
【发布时间】:2011-06-09 18:54:44
【问题描述】:

在 Rails 中,blocks can be used as callbacks,例如:

class User < ActiveRecord::Base
  validates_presence_of :login, :email

  before_create {|user| user.name = user.login.capitalize
    if user.name.blank?}
end

当这样使用块时,breakreturn 有什么用吗?我问是因为通常在一个块中,break 将跳出循环,return 将从封闭方法返回。但是在回调上下文中,我无法理解这意味着什么。

The Ruby Programming Language 建议 return 可能会导致 LocalJumpError 但我无法在 Rails 回调中重现这一点。


编辑:使用下面的代码,我希望有一个LocalJumpError,但return 所做的只是停止其余的回调执行。

class User < ActiveRecord::Base
  validates_presence_of :login, :email

  before_create do |user|
    return
    user.name = user.login.capitalize
end

【问题讨论】:

    标签: ruby-on-rails ruby block


    【解决方案1】:

    其实挺有意思的……

    当您在 Rails 3 中使用 before_create 时,我们会将您提供给我们的块或 lambda 转换为方法。然后我们使用当前的 ActiveRecord 对象调用该方法,以向后兼容旧的 Rails 方法。

    结果,下面相当于你的sn-p:

    class User < ActiveRecord::Base
      validates_presence_of :login, :email
    
      before_create do
        self.name = login.capitalize if name.blank?
      end
    end
    

    由于这种行为,您可以从块中调用 return,它的行为与普通方法中的 return 相同(因为它普通方法)。

    一般来说,块中的continue 从块中“返回”。

    普通方块的具体行为是:

    • 当您调用 continue 时,您将跳过该块的其余部分,并将控制权返回给调用该块的方法。
    • 当您调用 break 时,您将跳过该块的其余部分,并立即从调用该块的方法返回。

    您可以在普通迭代器中看到这种行为:

    value = [1,2,3,4].each do |i|
      continue if i == 2
      puts i
    end
    

    在这种情况下,value 将是 [1,2,3,4]each 方法的正常返回值,输出将是:

    1
    3
    4
    

    在break的情况下:

    value = [1,2,3,4].each do |i|
      break if i == 2
      puts i
    end
    

    在这种情况下,value 将是nil,因为break 也立即从each 方法返回。您可以使用break n 强制返回具有特定值的返回值,这将使valuen 相同。上述情况下的输出将是:

    1
    

    重要的是,continuebreak 不仅仅适用于迭代器,尽管它们的语义被设计成在迭代器的情况下表现得与 C 中的等价物一样。

    【讨论】:

    • 谢谢,这真的很有意义。
    【解决方案2】:

    return 在 Ruby 块中的操作取决于该块是使用 Proc.new 还是 lambda 构造的。

    我建议您阅读其他 Stack Overflow 问题中评分最高的答案:When to use lambda, when to use Proc.new?

    在这种情况下,块具有使用Proc.new 创建的块的属性。

    在这种回调的上下文中调用 return 只有在这也有意义的情况下才有意义(显然没有):

    class Foo
      return "bar"
    end

    【讨论】:

    • @Andy - 谢谢。在这种情况下,块是一个 Proc,但它不是用 Proc.newlambda 构造的——它是作为一个块传入的。还是你在before_create里面说的?
    • @Andy - 阅读了那个答案,问题是在这种情况下很明显return 将从包含方法返回。但是,如果它在类定义中,那么包含方法是什么?
    • 在这种情况下,回调基本上是一个Proc.new创建的块。
    • 那么如果我从那个街区回来,我会从什么地方回来?
    • 您正在退出创建它的上下文。如果在不同的上下文中执行,这会导致 LocalJumpError
    猜你喜欢
    • 2011-06-03
    • 1970-01-01
    • 1970-01-01
    • 2016-12-05
    • 1970-01-01
    • 2012-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多