一个ruby块中的参数数量

4

我是Ruby的新手,但不是第一次接触lambda表达式的语言,比如groovy。我看到了这个例子:

myArray.product(otherArray).reject{|i,j| i > j}

在一个Ruby代码块中,我之前从未见过这个块接受2个参数,但当我查看文档时,我只能看到文档显示它只接受1个参数。我查看了enumerable类的文档,但那个文档也只显示1个参数。
我知道它可以工作,但我希望有一种更简单的方法确定它需要多少个参数,而不是猜测和测试的方法。在Ruby中如何确定一个代码块需要多少个参数?
3个回答

9

这是因为Ruby支持解构。

解构允许你将一组变量绑定到一个对应的值集合,任何你通常可以将一个值绑定到单个变量的地方都可以使用它。

这使得以下内容成立:

arr = [1, 2]
x = arr
x == [1, 2] # true

y, z = arr
y == 1 # true
z == 2 # true

你可以从以下代码中看到,在参数解构到块中的情况下,并不仅限于需要块的内置方法:
def my_method(arr)
  yield arr
end

my_method([1, 2, 3]) {|x| puts x.inspect }
# => [1, 2, 3]
my_method([1, 2, 3]) {|x, y, z| puts x.inspect }
# => 1

查看Ruby的解构以获取更多信息。


正是我所需要的,解释了我不理解的内容,谢谢。 - Nicholas

3

根据数组的结构,您可以在块参数中进行一些有趣的重组:

[[1, 2], [3, 4], [5, 6], [7, 8]].reject {|x,y| y == 8 }
#=> [[1, 2], [3, 4], [5, 6]]

你可以使用括号对它们进行分组:
[ [[1,2],3], [[1,3],6] ].select {|(x,y),z| x == 1 && z == 3 }
#=> [ [[1,2],3] ]

您还可以使用展开运算符来处理各种事情,例如处理可变长度的子数组:
[[:a,:b,2,3,4,5,6], [:c,:d,7,8,9]].each {|x,y,*numbers| puts numbers.inspect }
#=> [2,3,4,5,6]
#=> [7,8,9]

虽然这展示了一些不错的例子,但我的问题更关注于如何能够确定哪些内容可以作为块的参数,例如当reject方法使用块时,你如何确定它传递了哪些参数。 - Nicholas

1

Ruby 在解释参数方面非常灵活;以下是一个类似的例子,分别为一个和两个参数:

[1, 3].product([2, 4]).reject {|a| a.first > a.last }
=> [[1, 2], [1, 4], [3, 4]] 
[1, 3].product([2, 4]).reject {|a,b| a > b }
=> [[1, 2], [1, 4], [3, 4]] 

这里的经验法则是,您可以将参数视为复合对象或集合中的单个元素。例如,
[1, 2, 3].tap {|a,b,c| puts [a,b,c].inspect }
[1, 2, 3]
... 
[1, 2, 3].tap {|a,b| puts [a,b].inspect }
[1, 2]
... 
[1, 2, 3].tap {|a| puts a.inspect }
[1, 2, 3]

我明白它是如何工作的,但我希望能有一种更简单的方法来确定它需要多少个参数,而不仅仅是猜测和测试的方式。 - Nicholas
大多数都相当灵活,但通常默认为一个参数。如果不确定,请查看文档。有一些通常需要两个参数,例如哈希枚举,在使用单个块参数时会产生一个两元素数组(例如 {:a => 1, :b => 2}.each {|x| ... } 使用 [:a,1][:b,2])。 - Zach Kemp
正如我所链接的,给出示例的文档 Array.reject 只显示一个参数,而代码则显示了一个或两个。 - Nicholas
@Nicholas:#reject 只是接受一个块参数。这里相关的是块的行为,而不是 #reject。正是块在解包参数或不解包参数,具有重要意义。 - Eric Walker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接