什么是允许块处理可变数量的参数的简洁方法?

Dan*_*Tao 4 ruby block proc

我之前遇到过这种情况,有些东西告诉我我一般处理它的方式不是最干净或最惯用的.

假设我有一个带块的函数,它可以依次取1或2个(比如说)参数.

def with_arguments(&block)
  case block.arity
  when 1
    block.call("foo")
  when 2
    block.call("foo", "bar")
  end
end

with_arguments do |x|
  puts "Here's the argument I was given: #{x}"
end

with_arguments do |x, y|
  puts "Here are the arguments I was given: #{x}, #{y}"
end
Run Code Online (Sandbox Code Playgroud)

打开arity看起来很漂亮.是否有更标准的Ruby方法来实现这种事情?

Mat*_*ira 6

这是我如何将任意参数传递给lambda:

def with_arguments(&block)
  args = %w(foo bar)
  n = block.arity
  block.call *(n < 0 ? args : args.take(n))
end

with_arguments &lambda { |foo| }
with_arguments &lambda { |foo, bar| }
with_arguments &lambda { |*args| }
with_arguments &lambda { |foo, *args| }
with_arguments &lambda { |foo, bar, *args| }
Run Code Online (Sandbox Code Playgroud)

如果n是否定的,则lambda采用任意数量的参数.准确地说(n + 1).abs,这些论点是强制性的.可以使用该信息来决定要传递的参数.

如果lambda获取有限数量的参数,那么只需传递第一个n元素args.如果它需要任意数量的参数,那么只需传递整个参数数组.

lambda本身将处理情况下args是不够的:

with_arguments &lambda { |foo, bar, baz, *args| }
# ArgumentError: wrong number of arguments (2 for 3)
Run Code Online (Sandbox Code Playgroud)

您只需将两个参数传递给块:

def with_arguments(&block)
  block.call 'foo', 'bar'
end

with_arguments { |x| puts x }              # y is not used
with_arguments { |x, y| puts x, y }        # All arguments are used
with_arguments { |x, y, z| puts x, y, z }  # z will be nil
Run Code Online (Sandbox Code Playgroud)

将丢弃未使用的块参数,并将任何其他参数设置为nil.

这是常规块特有的,Proclambda如果给出错误的参数数量,s - s将引发错误.您实际上可以通过调用来确定是否是这种情况Proc#lambda?

此外,如果您不打算存储块,只需使用它就更简洁yield:

def with_arguments
  yield 'foo', 'bar'
end
Run Code Online (Sandbox Code Playgroud)