Proc.arity与Lambda.arity

为什么proc和lambda为arity返回不同的值?

例如

proc { |x = 0| }.arity #=> 0 lambda { |a = 0| }.arity #=> -1 proc { |x=0, y| }.arity #=> 1 lambda { |x=0, y| }.arity #=> -2 

请参阅: http : //www.ruby-doc.org/core-2.0/Proc.html#method-i-arity

根据您链接到的文档:

返回不会被忽略的参数数。 如果声明该块不带参数,则返回0.如果已知该块正好采用n个参数,则返回n。 如果块具有可选参数,则返回-n-1,其中n是必需参数的数量。 没有参数声明的proc与声明||的块相同 作为其论点。

文档忘记提到的是,procs和lambda不会以完全相同的方式处理参数,例如:

 >> p = proc { |a = 1, b| b } => # >> l = lambda { |a = 1, b| b } => # >> p.call => nil >> l.call ArgumentError: wrong number of arguments (0 for 1..2) from (irb):2:in `block in irb_binding' from (irb):4:in `call' from (irb):4 from /usr/local/bin/irb:12:in `
'

编辑:来自O’Reilly的Ruby编程语言是一个有更多细节的编程语言:

6.5.3 Proc的Arity

proc或lambda的arity是它期望的参数数量。 (这个词来源于一元,二元,三元等的“ary”后缀。)Proc对象有一个arity方法,它返回它们期望的参数个数。 例如:

 lambda{||}.arity # => 0. No arguments expected lambda{|x| x}.arity # => 1. One argument expected lambda{|x,y| x+y}.arity # => 2. Two arguments expected 

当Proc在* -prefixed final参数中接受任意数量的论证时,arity的概念会变得混乱。 当Proc允许可选参数时,arity方法返回forms为-n-1的负数。 此表单的返回值表示Proc需要n个参数,但也可以选择使用其他参数。 -n-1被称为n的一个补码,你可以用〜运算符反转它。 因此,如果arity返回负数m,那么~m(或-m-1)将为您提供所需参数的数量:

 lambda {|*args|}.arity # => -1. ~-1 = -(-1)-1 = 0 arguments required lambda {|first, *rest|}.arity # => -2. ~-2 = -(-2)-1 = 1 argument required 

arity方法有一个最后的皱纹。 在Ruby 1.8中,可以使用任意数量的参数调用一个没有任何参数子句的Proc(也就是说,没有任何||字符)(并忽略这些参数)。 arity方法返回-1表示没有必需的参数。 这在Ruby 1.9中发生了变化:声明为此的Proc具有0的arity。如果它是lambda,则使用任何参数调用它是错误的:

 puts lambda {}.arity # –1 in Ruby 1.8; 0 in Ruby 1.9 

编辑2:Stefan在评论中添加了他们不同的确切原因:

http://www.ruby-doc.org/core-2.0/Proc.html#method-i-call

对于使用lambda->()创建的Proc ,如果将错误数量的参数传递给具有多个参数的Proc ,则会生成错误。 对于使用Proc.newKernel.proc创建的Kernel.proc ,将以静默方式丢弃其他参数。

如上所述:( Proc和Lambda之间的差异 ), proc和lambda之间的主要区别之一是“就像方法一样,lambdas有严格的参数检查,而非lambda Procs有松散的参数检查,就像块一样。”

因此,由于arity基于所需参数的数量,因此这将在procs和lambdas之间发生变化。

在阅读了其他2个答案之后,我的猜测是#arity方法正在踩着薄冰。 对于固定数量的有序参数, #arity曾经是完全正常的方法。 然后,当添加可选参数时,为了坚持单个整数的arity表示,减号被用作标志。 但是,已经丢弃了参数字段信息,例如。 1ary或2ary -> a, b=1 { a + b }表示相同的arity(-2)为-> a, *b { a + b.sum } ,取1到任意数量的参数。 在1.9中改变#arity行为之后,另一个打击在2.0,其中引入了命名参数,而#arity完全没有注意到。 同样,将有强制和可选的命名参数,以及使用散列值**收集任意数量的参数的可能性。 我希望#arity方法在将来再次改变它的行为……