4

我以前遇到过这种情况,有些事情告诉我我通常处理它的方式不是最干净或最惯用的。

假设我有一个接受一个块的函数,它又可以接受 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

打开arity似乎很hacky。有没有更标准的 Ruby 方法来实现这种事情?

4

3 回答 3

7

这是我将任意参数传递给 a 的方式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| }

如果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)

您可以简单地将两个参数传递给块:

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

未使用的块参数将被丢弃,任何额外的参数都将设置为nil.

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

此外,如果您不打算存储块,那么简单地使用yield

def with_arguments
  yield 'foo', 'bar'
end
于 2012-04-16T20:49:09.620 回答
0

一些解决方案...

  • 总是传递 2 个参数,即使一个必须为 nil
  • 只需传递一个数组,该数组可能包含更多或更少的元素。这种方式为您提供了两全其美:由于多重分配的工作方式,您可以省略或提供额外的块参数而不会发出警告
于 2012-04-16T20:37:36.277 回答
0
def bar(&block)
    puts 'In bar'
    block.call(1) if block
    puts 'Back in bar'
    block.call(1,2) if block
end

1.9.3p392 :043 > bar do |*b| puts b.length end
In bar
1
Back in bar
2
于 2014-07-29T10:25:17.167 回答