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はかなりハックなようです。この種のことを達成するためのより標準的なRubyの方法はありますか?

4

3 に答える 3

7

に任意の引数を渡す方法は次の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)

2 つの引数をブロックに渡すだけです。

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ます。

これは通常のブロックに固有Proclambdaのものであり、間違った数のパラメーターが指定された場合、s – s はエラーを発生させます。これが当てはまるかどうかは、実際に呼び出すことで確認できます。Proc#lambda?

また、ブロックを保存しない場合は、次のように単純に使用する方がクリーンですyield

def with_arguments
  yield 'foo', 'bar'
end
于 2012-04-16T20:49:09.620 に答える
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 に答える
0

いくつかの解決策...

  • 1つがnilでなければならない場合でも、常に2つのパラメーターを渡します
  • 1 つの配列を渡すだけで、要素の数が増減する場合があります。この種の方法により、両方の長所を活用できます。複数代入の仕組みにより、警告なしで除外したり、追加のブロック パラメーターを指定したりできます。
于 2012-04-16T20:37:36.277 に答える