在 Ruby 中,为什么要将 "yield" 包装在您正在拨打的电话中?

In Ruby, why wrap "yield" in a call you are making anyway?

我是 Ruby 的新手。我对在这里阅读的内容感到困惑:

http://alma-connect.github.io/techblog/2014/03/rails-pub-sub.html

他们提供此代码:

# app/pub_sub/publisher.rb
module Publisher
  extend self

  # delegate to ActiveSupport::Notifications.instrument
  def broadcast_event(event_name, payload={})
    if block_given?
      ActiveSupport::Notifications.instrument(event_name, payload) do
        yield
      end
    else
      ActiveSupport::Notifications.instrument(event_name, payload)
    end
  end
end

这样做有什么区别:

ActiveSupport::Notifications.instrument(event_name, payload) do
  yield
end

与这样做相比:

ActiveSupport::Notifications.instrument(event_name, payload)
yield

如果这是另一种语言,我可能会假设我们首先调用方法instrument(),然后我们调用yield 来调用block。但这不是他们写的。它们显示 yield 嵌套在 ActiveSupport::Notifications.instrument() 中。

我是否应该假设 ActiveSupport::Notifications.instrument() 正在返回某种可迭代对象,我们将对其进行迭代?我们是否为从 ActiveSupport::Notifications.instrument() 返回的每个项目调用一次 yield?

broadcast_event 方法被设计为接受可选的 block(允许您将代码块传递给该方法)。

ActiveSupport::Notifications.instrument 也有一个可选块。

您的第一个示例只是将传递给 broadcast_event 的块转发给 ActiveSupport::Notifications.instrument。如果没有块,你不能yield任何东西,因此调用不同。

虽然块经常用于迭代,但它们还有许多其他用途。一是确保适当的资源清理,例如

ActiveRecord::Base.with_connection do
  ...
end

检出线程的数据库连接,屈服于块,然后重新检入连接。

在仪器方法的特定情况下,您发现它所做的是添加到事件数据中,它即将广播有关它的块执行时间的信息。实际实现更复杂,但从广义上讲,它与

没有太大区别
event = Event.new(event_name, payload)
event.start = Time.now
yield 
event.end = Time.now 
event

yield 的使用允许它用一些计时代码包装代码的执行。在你的第二个例子中,没有块被传递给 instrument,它检测到这一点并将其记录为没有持续时间的事件