Ruby:如何检查一个块接受多少个参数?

Ruby:如何检查一个块接受多少个参数?,ruby,Ruby,我正在尝试设置一个方法,将块作为参数。我知道您通过给最后一个参数一个&prefix来实现这一点,但是一旦它被传递,我应该如何验证它 例如,如果我想验证一个参数是否是字符串,我可以使用is_a?(字符串)。但是我如何验证我收到了一个接受一个参数的块?或2?您可以使用Proc#arity方法检查块接受的参数数量: def foo(&block) puts block.arity end foo { } # => 0 foo { |a| } # => 1

我正在尝试设置一个方法,将块作为参数。我知道您通过给最后一个参数一个&prefix来实现这一点,但是一旦它被传递,我应该如何验证它

例如,如果我想验证一个参数是否是字符串,我可以使用
is_a?(字符串)
。但是我如何验证我收到了一个接受一个参数的块?或2?

您可以使用
Proc#arity
方法检查块接受的参数数量:

def foo(&block)
  puts block.arity
end

foo { }        # => 0
foo { |a| }    # => 1
foo { |a, b| } # => 2
从文件中:

返回不会被忽略的参数数。如果 块声明为不带参数,返回0。如果街区是 已知只接受n个参数,返回n。如果街区有 可选参数,返回-n-1,其中n是必需参数的数目 论据。没有参数声明的proc与块是相同的 宣布| |为其论点


块不是对象,所以你不能用它们做任何有用的事情(当然,除了
让它们产生

我的意思是,没有办法提及它们,它们甚至不受名字的约束:

def foo
  yield 'foo'
end

foo do |bar| puts bar end
# foo
foo
内部,块没有绑定到任何变量,您甚至不能引用它,因此您显然也不能查询它的参数

但是,您可以要求Ruby将块转换为
Proc
,并将其绑定到参数。然后,您可以按名称引用它,并且您可以使用完整的
Proc
API,包括
Proc#参数

def foo(&blk)
  blk.parameters
end

foo do |m1, m2, o1=:o1, o2=:o2, *splat, m3, m4, 
      ok1: :ok1, mk1:, mk2:, ok2: :ok2, **ksplat, &blk| end
# => [[:opt, :m1],
#     [:opt, :m2],
#     [:opt, :o1],
#     [:opt, :o2],
#     [:rest, :splat],
#     [:opt, :m3],
#     [:opt, :m4],
#     [:keyreq, :mk1],
#     [:keyreq, :mk2],
#     [:key, :ok1],
#     [:key, :ok2],
#     [:keyrest, :ksplat],
#     [:block, :blk]]
然而,请注意,在Ruby中,“块的arity”的概念是一个毛茸茸的概念,因为块的松散参数绑定语义。块的参数绑定语义不同于方法的参数绑定语义,尤其是在arity方面:

  • 如果块只接受一个参数,但传递了多个参数,则这不是错误,而是将参数作为绑定到参数的单个
    数组
    传递(就好像该参数已声明为
    *splat
    参数一样)
  • 如果块接受多个参数,但只传递一个参数,则该参数将转换为
    数组
    ,其各个元素将作为参数传递(就像它们已作为
    *splat
    参数传递一样)
  • 如果传递的参数多于块接受的参数,则会忽略额外的参数
  • 如果传递的参数少于块接受的参数,则额外的参数将绑定到
    nil
总而言之,语义比方法调用更接近赋值

例如,您会注意到,即使
m1
m2
被声明为块中的强制位置参数,
Proc#parameters
将其类型列为
:opt
,即可选参数

换句话说:即使一个只声明一个参数的块仍然需要两个参数,而一个声明两个参数的块只需要一个参数就可以调用


一个有用的例子是:整个
可枚举的
mixin基于
产生
单个元素的方法。但是,对于
Hash
,您确实需要处理两个参数,
key,value
。您可以,因为
Hash#每个
产生一个由两个元素组成的
数组,一个声明两个参数但只接收一个参数的块将在其参数中“splat”该参数,这样,您就可以将键绑定到
key
并将值绑定到
value
,而不必复制和粘贴所有
Enumerable
s方法的两个参数版本。

注意:可选参数后的强制参数在1.9中是新的,关键字参数在2.0中是新的,强制关键字参数在2.1中是新的。否则,您将得到一个
SyntaxError
。我只是想展示
Proc#parameters
的全部功能(以及
Proc#arity
在存在关键字参数时越来越无用。)