Why do Ruby procs/blocks with splat arguments behave differently than methods and lambdas?

别来无恙 提交于 2019-12-18 16:46:22

问题


Why do Ruby (2.0) procs/blocks with splat arguments behave differently than methods and lambdas?

def foo (ids, *args)
  p ids
end
foo([1,2,3]) # => [1, 2, 3]

bar = lambda do |ids, *args|
  p ids
end
bar.call([1,2,3]) # => [1, 2, 3]

baz = proc do |ids, *args|
  p ids
end
baz.call([1,2,3]) # => 1

def qux (ids, *args)
  yield ids, *args
end
qux([1,2,3]) { |ids, *args| p ids } # => 1

Here's a confirmation of this behavior, but without explanation: http://makandracards.com/makandra/20641-careful-when-calling-a-ruby-block-with-an-array


回答1:


There are two types of Proc objects: lambda which handles argument list in the same way as a normal method, and proc which use "tricks" (Proc#lambda?). proc will splat an array if it's the only argument, ignore extra arguments, assign nil to missing ones. You can partially mimic proc behavior with lambda using destructuring:

->((x, y)) { [x, y] }[1]         #=> [1, nil]
->((x, y)) { [x, y] }[[1, 2]]    #=> [1, 2]
->((x, y)) { [x, y] }[[1, 2, 3]] #=> [1, 2]
->((x, y)) { [x, y] }[1, 2]      #=> ArgumentError



回答2:


Just encountered a similar issue!

Anyways, my main takeaways:

  1. The splat operator works for array assignment in a predictable manner

  2. Procs effectively assign arguments to input (see disclaimer below)

This leads to strange behavior, i.e. the example above:

baz = proc do |ids, *args|
  p ids
end
baz.call([1,2,3]) # => 1

So what's happening? [1,2,3] gets passed to baz, which then assigns the array to its arguments

ids, *args = [1,2,3]
ids = 1
args = [2,3]

When run, the block only inspects ids, which is 1. In fact, if you insert p args into the block, you will find that it is indeed [2,3]. Certainly not the result one would expect from a method (or lambda).

Disclaimer: I can't say for sure if Procs simply assign their arguments to input under the hood. But it does seem to match their behavior of not enforcing the correct number of arguments. In fact, if you give a Proc too many arguments, it ignores the extras. Too few, and it passes in nils. Exactly like variable assignment.



来源:https://stackoverflow.com/questions/23945533/why-do-ruby-procs-blocks-with-splat-arguments-behave-differently-than-methods-an

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!