【问题标题】:Kernel.lambda() not returning a lambda Proc in Ruby 1.9Kernel.lambda() 在 Ruby 1.9 中不返回 lambda Proc
【发布时间】:2012-07-24 07:34:46
【问题描述】:

我正在编写一个在应用程序中使用的简单事件总线。这部分工作正常:

#!/usr/bin/env ruby

module EventBus
  @callbacks = {}

  module_function

  def on event, &callback
    @callbacks[event] ||= []
    @callbacks[event].push callback
  end

  def fire event, *data
    @callbacks[event].each do |callback|
      callback.call *data
    end
  end
end

EventBus.on :foo do |x| puts x end
EventBus.fire :foo, "test"
# => test

由于我的程序的复杂性,以及Procs 以非常松散的方式接受参数的事实,我希望对我的事件进行一些参数检查。 lambda 是显而易见的选择:

EventBus.on :bar, &(lambda do |x| puts x end)

# Will raise an ArgumentError, since the event was fired without any arguments
# Remember that this is the desired behavior
EventBus.fire :bar

显然,由于&(lambda do ... end)on 调用的语法很难看。我宁愿能够只使用 do ... end (即,只需将其传递给没有一元 & 运算符的普通块)并将其转换为 lambda。我尝试了明显的:

...
  def on_lambda event, &callback
    @callbacks[event] ||= []
    @callbacks[event].push(lambda &callback)
    # check if the added callback is lambda. (spoiler alert: it isn't)
    puts @callbacks[event].last.lambda?
  end
end

EventBus.on_lambda :baz do |x| puts x end
# I would expect the callback to be a lambda, and thus throw an ArgumentError,
# but neither of these holds.
EventBus.fire :baz

据我了解,on_lambda 接受一个块,将其转换为由callback 本地引用的Proc(通过&)。我正在推动调用lambda 的结果,并将callback 转换回一个块。我希望这会返回从callbackProc 派生的 lambda,所以我的问题是:为什么数组上的元素是普通的Proc

ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-linux]


更新: 在 megas 提到 { } 的提示下,我查看了 ->() { } 语法(我已经看到它被称为“stab”运算符)。它从指定的块中生成一个 lambda。它可能与我想要的普通块语法和参数检查的混合一样接近。我所要做的就是调整on 方法:
def on event, callback
  @callbacks[event] ||= []
  @callbacks[event].push callback
end

然后像这样附加回调:

EventBus.on :bam, ->(x) do
  puts x
end

不过,我仍然对最初的问题感到好奇。

【问题讨论】:

  • 对于一个行块使用 {} 的代码约定怎么样?
  • 据我所知,这相当于do ... end,除了优先级。回调在我的应用程序中几乎不会是一行,并且使用该语法也不会产生 lambda Proc。

标签: ruby lambda block ampersand ruby-1.9.3


【解决方案1】:

【讨论】:

  • RTFM。一个古老的经典。具体来说:“lambdaproc::new 保留了 & 参数给出的 Proc 对象的技巧。”
【解决方案2】:

传递给方法调用的块总是打包为 Procs。如果你想要 lambdas,你必须明确地构造它们,通过说 lambda {|...| ... }。顺便提一句。我也比 procs 更喜欢 lambdas,但如果我没记错的话,Matz 在他的教程中介绍 procs 比 lambdas “更有特色”(procs“有技巧”适应可变数量的参数等,而 lambdas 没有)。

你必须做这样的事情来传递 lambdas:

def on_lambda event, callback
  (@callbacks[event] ||=[]) << callback
  puts @callbacks[event].last.lambda?
end

EventBus.on_lambda :baz, lambda do |x| puts x end
EventBus.fire :baz

【讨论】:

  • 这对我来说都很有意义,但是在on_lambda 中,我通过一元 &amp; 运算符将 Proc 传递回 lambda,这应该将其转换回一个块(应该是为什么lambda 本身没有提出ArgumentError,如果我理解正确的话)。
  • 另外,Proc 的“技巧”通常很漂亮,但在这种情况下特别不受欢迎,因为我想要严格的参数检查。
  • 一旦你开始用 & 打包和解包块 ... 这不是真正的操作符,但更像是 splash * for blocks ...我的意思是,一旦你开始使用 &,你'重新陷入 procs。我建议你用别名修补你的内核 :λ :lambda ^_^
猜你喜欢
  • 1970-01-01
  • 2010-09-06
  • 1970-01-01
  • 2012-09-24
  • 1970-01-01
  • 2011-02-26
  • 2018-12-28
  • 2012-02-12
  • 1970-01-01
相关资源
最近更新 更多