简体   繁体   中英

Number of arguments in a ruby block

I'm new to Ruby, but not to languages that allow lambda's, such as groovy. So I saw this example:

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

in a ruby code block, and I hadn't seen this block take 2 arguments before, but when I went to look at the documentation I can only see the documentation that says that it takes 1 argument. I looked at the same for the enumerable class, but that doc only shows 1 argument also.

I understand that it works, I guess I was hoping that there was an easier way to determine how many arguments it takes other then a guess and test method. How can I tell how many arguments a block takes in Ruby?

This works because Ruby supports destructuring.

Destructuring allows you to bind a set of variables to a corresponding set of values anywhere that you can normally bind a value to a single variable.

This allows the following to hold true:

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

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

You can see from the following code that destructuring in arguments to blocks isn't unique to the built-in methods that take a block:

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

Check out Destructuring with Ruby for more information.

You can do some interesting restructuring in block parameters, depending on the structure of your array:

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

You can group them in parentheses:

[ [[1,2],3], [[1,3],6] ].select {|(x,y),z| x == 1 && z == 3 }
#=> [ [[1,2],3] ]

You can also use the splat operator for various things, like dealing with variable-length subarrays:

[[: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]

Ruby is flexible in how it interprets the arguments; here is a similar example, with one and then two arguments:

[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]] 

The rule of thumb here is that you can treat the arguments either as a composite object, or as individual elements in a collection. Eg,

[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]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM