当用作回调时,Ruby 块中的“return”和“break”是不是无用?

Posted

技术标签:

【中文标题】当用作回调时,Ruby 块中的“return”和“break”是不是无用?【英文标题】: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

【问题讨论】:

【参考方案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

以上是关于当用作回调时,Ruby 块中的“return”和“break”是不是无用?的主要内容,如果未能解决你的问题,请参考以下文章

在 Ruby 块中使用“返回”

Nodejs:catch块中的回调函数在try-catch中返回未定义的参数

Java中,finally在try语句块中的return前执行还是后执行

Java中,finally在try语句块中的return前执行还是后执行

当对象的方法之一用作其自身属性的回调时,如何调用对象的析构函数?

iOS 中的 iBeacons - 没有来自实际 BLE 设备的回调,但是当另一个 iOS 设备用作广播器时会调用 didRangeBeacons