3

Josh Susserから次の例を取り上げました。

  def strip_accents params
    thunk = lambda do |key,value|
      case value
        when String then value.remove_accents!
        when Hash   then value.each(&thunk)
      end
    end
    params.each(&thunk)
  end

Railsコンソール(irb)に入れ、ハッシュで呼び出すと、次のようになります。

ruby-1.9.2-p136 :044 > `ruby --version`
 => "ruby 1.9.2p136 (2010-12-25 revision 30365) [i686-linux]\n"
ruby-1.9.2-p136 :045 > strip_accents({:packs=>{:qty=>1}})
ArgumentError: wrong number of arguments (1 for 2)
        from (irb):32:in `block in strip_accents'
        from (irb):37:in `each'
        from (irb):37:in `strip_accents'
        from (irb):45
        from /longpathtrimedforclarity/console.rb:44:in `start'
        from /longpathtrimedforclarity/console.rb:8:in `start'
        from /longpathtrimedforclarity/commands.rb:23:in `<top (required)>'
        from script/rails:6:in `require'
        from script/rails:6:in `<main>'

ラムダがアリティをチェックすることは理解していますが、ラムダの定義に 2 つの引数があります。に変更lambda doするとProc.new do、コードが実行され、期待される結果が得られます。

Josh の例は 2008 年のものなので、これは Ruby 1.8 と 1.9 の違いだと思います。何が起きてる?

4

2 に答える 2

3

実際、1.8 と 1.9 の間で変更されたように見えますが、この変更により、少なくとも私のテストでは 1.9.2 で修正されます。

def strip_accents params
  thunk = lambda do |h|
    key, value = h
    case value
    when String then value.remove_accents!
    when Hash   then value.each(&thunk)
    end
  end
  params.each(&thunk)
end

このアプローチは、Ruby 1.8.7 との下位互換性もあることが判明しました。

于 2011-03-10T16:56:33.090 に答える
1

Hash#eachは、他のすべての#eachメソッドと同様に、ブロックに1 つの引数を与えます。の場合Hash#each、その 1 つの引数は、キーと値で構成される 2 要素の配列です。

したがって、1 つのHash#each引数が生成されますが、ラムダには2 つの必須パラメーターがあるため、アリティ エラーが発生します。

ブロックは引数についてそれほど厳密ではないため、ブロックで機能します。特に、ブロックに複数のパラメーターがあり、1 つの引数しか取得できない場合、あたかもスプラットで渡されたかのように、引数を分解しようとします。

Procs には、ラムダと非ラムダの2 種類があります(紛らわしいことに、後者は通常Procs とも呼ばれます)。ラムダは、キーワードの動作と (この場合はさらに重要なことですが) 引数をバインドする方法に関してメソッドのようにreturn動作しますが、非ラムダは、引数バインディングProcの動作方法と動作に関してブロックのように動作します。returnそのため、Proc.new(非ラムダを作成する) は機能しますProcが、lambda(明らかにラムダを作成する) は機能しません。

Procを呼び出して、 a がラムダかどうかを確認できますProc#lambda?

引数を分解したい場合は、メソッドを定義するときと同じように、明示的に行う必要があります。

lambda do |(key, value)|

Procそして、そうです、ブロック、 s 、およびラムダの引数バインディングに対するより健全なアプローチ、Ruby 1.9 における後方互換性のない主要な変更の 1 つです。

于 2011-03-10T22:37:15.467 に答える