14

为什么 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

4

3 回答 3

14

根据您链接到的文档:

返回不会被忽略的参数的数量。如果该块被声明为不带参数,则返回 0。如果已知该块恰好带 n 个参数,则返回 n。如果块有可选参数,则返回 -n-1,其中 n 是强制参数的数量。没有参数声明的 proc 与声明 || 的块相同 作为它的论据。

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

>> p = proc { |a = 1, b| b }
=> #<Proc:0x007ff0091ef810@(irb):1>
>> l = lambda { |a = 1, b| b }
=> #<Proc:0x007ff0098099f8@(irb):2 (lambda)>
>> 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 `<main>'

编辑:来自 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 在以 * 为前缀的最终参数中接受任意数量的参数时,arity 的概念会变得混乱。当 Proc 允许可选参数时,arity 方法返回 -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。如果它是 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

For procscreated usinglambda->()如果将错误数量的参数传递给Proc具有多个参数的 a ,则会生成错误。对于procs使用Proc.newor创建Kernel.proc的,额外的参数会被静默丢弃。

于 2013-06-07T14:43:34.887 回答
2

正如这里提到的:( Proc 和 Lambda 之间的差异),procs 和 lambda 之间的主要区别之一是“就像方法一样,lambdas 具有严格的参数检查,而非 lambda Procs 具有松散的参数检查,就像块一样。”

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

于 2013-06-07T14:44:44.087 回答
2

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

于 2013-06-07T20:30:10.557 回答