Ruby Hash.each和lambdas之间的算术不一致

Ruby Hash.each和lambdas之间的算术不一致,ruby,lambda,closures,proc-object,Ruby,Lambda,Closures,Proc Object,我从中举出了下面的例子 当我把它放在rails控制台(irb)中,并用散列函数调用它时,我得到以下结果: ruby-1.9.2-p136 :044 > `ruby --version` => "ruby 1.9.2p136 (2010-12-25 revision 30365) [i686-linux]\n" ruby-1.9.2-p136 :045 > strip_accents({:packs=>{:qty=>1}}) ArgumentError: wrong

我从中举出了下面的例子

当我把它放在rails控制台(irb)中,并用散列函数调用它时,我得到以下结果:

ruby-1.9.2-p136 :044 > `ruby --version`
 => "ruby 1.9.2p136 (2010-12-25 revision 30365) [i686-linux]\n"
ruby-1.9.2-p136 :045 > strip_accents({:packs=>{:qty=>1}})
ArgumentError: wrong number of arguments (1 for 2)
        from (irb):32:in `block in strip_accents'
        from (irb):37:in `each'
        from (irb):37:in `strip_accents'
        from (irb):45
        from /longpathtrimedforclarity/console.rb:44:in `start'
        from /longpathtrimedforclarity/console.rb:8:in `start'
        from /longpathtrimedforclarity/commands.rb:23:in `<top (required)>'
        from script/rails:6:in `require'
        from script/rails:6:in `<main>'
ruby-1.9.2-p136:044>`ruby--version`
=>“ruby 1.9.2p136(2010-12-25修订版30365)[i686 linux]\n”
ruby-1.9.2-p136:045>带口音({:packs=>{:qty=>1})
ArgumentError:参数数目错误(1代表2)
from(irb):32:in“带重音的方块”
from(irb):37:in'each'
来自(irb):37:用“脱衣舞口音”
起始(irb):45
from/longpathtrimedforclarity/console.rb:44:in'start'
from/longpathtrimedforclarity/console.rb:8:in'start'
from/longpathmedforclearity/commands.rb:23:in`'
来自脚本/rails:6:in'require'
来自脚本/rails:6:in`'
我知道lambda检查算术,但我在lambda定义中看到两个参数。如果我将
lambda do
更改为
Proc.new do
,代码将执行,并获得预期结果


Josh的例子是2008年的,所以我假设这是Ruby1.8和1.9的一个区别。这是怎么回事?

事实上,它似乎在1.8和1.9之间发生了变化,但这一变化将其修正为1.9.2,至少在我的测试中是这样的:

def strip_accents params
  thunk = lambda do |h|
    key, value = h
    case value
    when String then value.remove_accents!
    when Hash   then value.each(&thunk)
    end
  end
  params.each(&thunk)
end
这种方法也与Ruby 1.8.7向后兼容。

Hash#每个
,就像其他每个方法一样,每个方法都为块生成一个参数。对于
散列#each
,一个参数是由键和值组成的两元素数组

因此,
Hash#每个
都会产生一个参数,但是lambda有两个强制参数,因此会出现一个算术错误

它适用于块,因为块对其参数不太严格,特别是,如果块有多个参数,但只得到一个参数,它将尝试解构该参数,就像它是通过splat传入的一样

有两种
Proc
s:lambda和non-lambda(令人困惑的是,后者通常也称为
Proc
s)。lambda在
return
关键字的行为以及(更重要的是,在本例中)它们如何绑定参数方面的行为类似于方法,而非lambda
Proc
s在
return
和参数绑定工作方面的行为类似于块。这就是为什么
Proc.new
(它创建了一个非lambda
Proc
)可以工作,但是
lambda
(它显然创建了一个lambda)不能工作的原因

您可以通过调用
Proc#lambda?
来检查
Proc
是否为lambda

如果要解构参数,必须显式解构,与定义方法时的解构方式相同:

lambda do |(key, value)|

是的,一种更明智的块参数绑定方法,
Proc
s和lambdas是Ruby 1.9中主要的向后不兼容更改之一。

FWIW,鹤嘴锄使用术语“raw Proc”来区分Proc风格的Proc和lambda风格的Proc。不过,我不认为这完全是教科书上的利斯科夫替代原则行为。
lambda do |(key, value)|