342

Ruby 1.8 では、proc/lambda との間に微妙な違いがありProc.newます。

  • それらの違いは何ですか?
  • どちらを選択するかを決定する方法について、ガイドラインを教えていただけますか?
  • Ruby 1.9 では、proc と lambda が異なります。どうしたんだ?
4

14 に答える 14

380

lambdaで作成されたprocとで作成されたprocのもう1つの重要ですが微妙な違いは、ステートメントProc.newの処理方法です。return

  • lambda-created procでは、ステートメントreturnはproc自体からのみ返されます
  • Proc.new-created procでは、returnステートメントはもう少し驚くべきものです。procからだけでなく、procを囲むメソッドからも制御を返します

lambdaこれが-createdprocの動作returnです。それはおそらくあなたが期待する方法で動作します:

def whowouldwin

  mylambda = lambda {return "Freddy"}
  mylambda.call

  # mylambda gets called and returns "Freddy", and execution
  # continues on the next line

  return "Jason"

end


whowouldwin
#=> "Jason"

これがProc.new-createdprocreturnが同じことをしているところです。Rubyが驚き最小の原則を破るケースの1つを目にするところです。

def whowouldwin2

  myproc = Proc.new {return "Freddy"}
  myproc.call

  # myproc gets called and returns "Freddy", 
  # but also returns control from whowhouldwin2!
  # The line below *never* gets executed.

  return "Jason"

end


whowouldwin2         
#=> "Freddy"

この驚くべき振る舞い(およびタイピングの減少)のおかげで、私はprocを作成するときに使用lambdaすることを好む傾向がProc.newあります。

于 2008-08-03T15:21:52.760 に答える
42

との違いを示すこのページを見つけました。ページによると、唯一の違いは、ラムダが受け入れる引数の数について厳密であるのに対し、欠落している引数を に変換することです。違いを示す IRB セッションの例を次に示します。Proc.newlambdaProc.newnil

irb(メイン):001:0> l = ラムダ { |x, y| x + y }
=> #<Proc:0x00007fc605ec0748@(irb):1>
irb(main):002:0> p = Proc.new { |x, y| x + y }
=> #<Proc:0x00007fc605ea8698@(irb):2>
irb(main):003:0> l.call "hello", "world"
=>「ハローワールド」
irb(main):004:0> p.call "hello", "world"
=>「ハローワールド」
irb(main):005:0> l.call "hello"
ArgumentError: 引数の数が間違っています (1 対 2)
    (irb) から:1
    from (irb):5:in `call'
    から (irb):5
    から:0
irb(メイン):006:0> p.call "こんにちは"
TypeError: nil を String に変換できません
    from (irb):2:in `+'
    から (irb):2
    from (irb):6:in `call'
    から (irb):6
    から:0

このページでは、特にエラー トレラントな動作が必要でない限り、ラムダの使用も推奨しています。私はこの感情に同意します。ラムダを使用すると、少し簡潔に見えますが、そのようなわずかな違いがあるため、平均的な状況ではより良い選択のようです。

Ruby 1.9 については、申し訳ありませんが、まだ 1.9 を調べていませんが、それほど変更されるとは思いません (私の言葉を鵜呑みにしないでください。いくつかの変更について聞いたことがあるようですので、私はおそらくそこで間違っています)。

于 2008-08-03T07:28:54.070 に答える
15

Proc は古いですが、return のセマンティクスは私にとって非常に直感に反するものです (少なくとも私が言語を学んでいたとき)。

  1. proc を使用している場合は、何らかの機能パラダイムを使用している可能性があります。
  2. Proc は、囲んでいるスコープから戻ることができます (以前の回答を参照)。これは基本的に goto であり、本質的に非常に機能的ではありません。

ラムダは機能的により安全で、理由を簡単に説明できます。私は常に proc の代わりにラムダを使用しています。

于 2008-09-10T23:32:34.683 に答える
11

微妙な違いはなんとも言えません。ただし、Ruby 1.9 では、ラムダとブロックのオプションのパラメーターが許可されるようになったことを指摘できます。

1.9 未満の stabby ラムダの新しい構文は次のとおりです。

stabby = ->(msg='inside the stabby lambda') { puts msg }

Ruby 1.8 にはその構文がありませんでした。ブロック/ラムダを宣言する従来の方法も、オプションの引数をサポートしませんでした。

# under 1.8
l = lambda { |msg = 'inside the stabby lambda'|  puts msg }
SyntaxError: compile error
(irb):1: syntax error, unexpected '=', expecting tCOLON2 or '[' or '.'
l = lambda { |msg = 'inside the stabby lambda'|  puts msg }

ただし、Ruby 1.9 では、古い構文でもオプションの引数がサポートされています。

l = lambda { |msg = 'inside the regular lambda'|  puts msg }
#=> #<Proc:0x0e5dbc@(irb):1 (lambda)>
l.call
#=> inside the regular lambda
l.call('jeez')
#=> jeez

Leopard または Linux 用の Ruby1.9 をビルドしたい場合は、この記事(恥知らずな自己宣伝) を参照してください。

于 2008-11-19T21:28:28.783 に答える
11

これを確認する良い方法は、ラムダが独自のスコープで (メソッド呼び出しであるかのように) 実行されることですが、Procs は呼び出し元のメソッドとインラインで実行されると見なすことができます。少なくとも、どちらを使用するかを決定する良い方法です。いずれの場合にも。

于 2008-12-09T14:17:51.017 に答える
11

簡単な答え: 重要なのは何をするかreturnです: lambda はそれ自体から戻り、proc はそれ自体とそれを呼び出した関数から戻ります。

あまり明確でないのは、それぞれを使用する理由です。ラムダは、関数型プログラミングの意味で物事が行うべきだと私たちが期待するものです。これは基本的に、現在のスコープが自動的にバインドされた匿名メソッドです。2 つのうち、おそらくラムダを使用する必要があります。

一方、Proc は、言語自体の実装に非常に役立ちます。たとえば、「if」ステートメントや「for」ループを実装できます。proc で見つかった return は、"if" ステートメントだけでなく、それを呼び出したメソッドからも返されます。これは言語がどのように機能し、「if」ステートメントがどのように機能するかです。私の推測では、Ruby はこれを隠れて使用し、強力に見えたので公開しただけです。

これは、ループや if-else 構造などの新しい言語構造を作成する場合にのみ必要です。

于 2011-10-06T18:33:20.840 に答える
7

クエストの3番目のメソッドである「proc」についてはコメントがありません。これは非推奨ですが、1.8と1.9では処理が異なります。

これはかなり冗長な例で、3つの類似した呼び出しの違いを簡単に確認できます。

def meth1
  puts "method start"

  pr = lambda { return }
  pr.call

  puts "method end"  
end

def meth2
  puts "method start"

  pr = Proc.new { return }
  pr.call

  puts "method end"  
end

def meth3
  puts "method start"

  pr = proc { return }
  pr.call

  puts "method end"  
end

puts "Using lambda"
meth1
puts "--------"
puts "using Proc.new"
meth2
puts "--------"
puts "using proc"
meth3
于 2009-06-25T11:22:32.633 に答える
6

Closures in Rubyは、ブロック、ラムダ、およびプロシージャが Ruby で Ruby を使用してどのように機能するかについての概要です。

于 2008-08-28T13:50:12.320 に答える
3

アコーディオンガイの応答について詳しく説明するには:

Proc.newブロックが渡されることによってprocoutを作成することに注意してください。lambda {...}これは、ブロックを渡すメソッド呼び出しではなく、一種のリテラルとして解析される と思います。returnメソッド呼び出しにアタッチされたブロックの内側から実行すると、ブロックではなくメソッドから返されますProc.new。ケースは、この例です。

(これは1.8です。これが1.9にどのように変換されるかはわかりません。)

于 2008-09-07T02:31:40.607 に答える
3

私はこれに少し遅れていますがProc.new、コメントでまったく言及されていないことについて、あまり知られていない素晴らしいことが1つあります. ドキュメントによると:

Proc::newは、ブロックが添付されたメソッド内でのみ、ブロックなしで呼び出すことができます。この場合、そのブロックはProcオブジェクトに変換されます。

そうは言っても、Proc.newyielding メソッドを連鎖させましょう。

def m1
  yield 'Finally!' if block_given?
end

def m2
  m1 &Proc.new
end

m2 { |e| puts e } 
#⇒ Finally!
于 2015-04-28T13:15:25.247 に答える
1

との動作の違いreturnは、私見ですが、2つの間の最も重要な違いです。Proc.newよりも入力が少ないため、ラムダも好みます:-)

于 2008-08-11T02:09:46.683 に答える