4

ここでRubyとStackOverflownewbは、Rubyを通り抜けて、最初の大きな障害にぶつかりました。ProcsとLambdasに頭を巻くのに本当に苦労しています。これが私が使っているコードです。

def procBuilder(message)
  Proc.new{ puts message; return}
end

def test
  puts "entering method"
  p = procBuilder("entering proc")
  p.call
  puts "exit method"
end

test

設計上、これはLocalJumpErrorをスローすることですが、その理由は正しくわかりません。これが何をしたかを推測する必要がある場合、p = procBuilder( "entering proc")の実行時に最初に "entering proc"を出力し、p.callによって渡される文字列がないため、p.callでエラーをスローすると推測します。 、しかし明らかに私はそれらの2つの行の間に起こっている重要な何かを見逃しています。また、これがprocではなくlambdaで機能する理由も完全には理解していませんが、エラーを理解することでその問題も解決されると思います。

明確化してくれてありがとう

4

2 に答える 2

4

これは、関連する質問に対する回答ですラムダと proc および LocalJumpErrors について少し説明します。

procでは、proc 自体ではなく、proc のレキシカルスコープreturnから返される特別な構文です。そのため、すでに終了しているから戻ろうとしています。procBuilder

これを修正するには、いくつかの方法があります。

  1. 絶対に使わないreturnでください。Ruby は、proc の呼び出し元にすべて独自に制御を返します。
  2. に変更procするとlambda、期待どおりに動作します。ラムダはメソッドのように機能します。proc はブロックのように機能します。

あなたが期待しているエラーに関しては、それを得るべきではありません。procBuilderメッセージ変数を囲む proc を返します。proc 自体への引数は必要ありません。

編集:追加の質問に答えます。proc はクロージャーです。procBuilderproc が作成されたときにスコープ内にあったメッセージ変数 ( のローカル変数) を「キャプチャ」しました。proc は、メッセージ変数が内部に隠されている状態でプログラムをさまようことができ、呼び出したときに出力する準備ができています。唯一の問題は return ステートメントです。これには、レキシカル スコープがまだ「有効」であるという追加の要件があります。

このすべての理由は、この動作がブロックで非常に役立つからです。この場合、それはまったく役に立たないので、単に a を使用する必要がありますlambda。ここで、 return はそれほど狂っていないことを意味します。

Ruby のクロージャーに関する非常に優れたチュートリアル: http://innig.net/software/ruby/closures-in-ruby.rb

于 2011-11-17T06:19:44.593 に答える
0

proc とメソッドまたはラムダの重要な違いは、return ステートメントを処理する方法です。メソッドが別のメソッド内で定義されている場合、内部メソッドの return ステートメントは内部メソッド自体からのみ終了し、外部メソッドは実行を継続します。同じことが、ラムダ内のラムダ、メソッド内のラムダ、またはラムダ内のメソッドの定義にも当てはまります。ただし、proc がメソッド内で定義されている場合、return ステートメントは proc および外側の (囲んでいる) メソッドから終了します。例:

def meditate
    puts "Adjusting posture…"
    p = Proc.new { puts "Ringing bell…"; return }
    p.call
    puts "Sitting still…"  # This is not executed
end

meditate

Output:
Adjusting posture…
Ringing bell…

proc 内の return ステートメントが proc と外側のメソッドの両方から終了したため、メソッドの最後の行が実行されていないことに注意してください。

外側のメソッドなしで proc を定義し、return ステートメントを使用すると、LocalJumpError がスローされます。

p = Proc.new { puts "Ringing bell…"; return }
p.call
Output:
Ringing bell…
LocalJumpError: unexpected return

これは、return ステートメントが proc 内で到達したときに、それが呼び出されたコンテキストから戻るのではなく、それ (proc) が定義されたスコープから戻るために発生します。次の例では、proc が定義された最上位の環境から返そうとしているため、LocalJumpError が発生します。

def meditate p
    puts "Adjusting posture…"
    p.call
    puts "Sitting still…"  # This is not executed
end

p = Proc.new { puts "Ringing bell…"; return }

meditate p
Output:
Adjusting posture…
Ringing bell…
LocalJumpError: unexpected return

通常、proc 内で return ステートメントを使用することはお勧めできません。通常、proc はメソッド間で渡され、proc が定義されたメソッドが既に返されている場合は、例外がスローされます。以下の例では、return ステートメントを削除するだけです。ただし、実際に何かを返す必要がある場合があります。後者では、proc の代わりに lambda を使用するのがおそらく最善です。後で、ラムダが return ステートメントを別の方法で、よりメソッドのように処理することを確認します。

以下は、return ステートメントを含む別のシナリオです。

def zafu_factory
    # This method will return the following proc implicitly
    Proc.new { puts "Round black zafu"; return }
end

def meditate
    puts "Adjusting posture…"
    p = zafu_factory
    p.call
    puts "Sitting still…"  # This is not executed
end

meditate
Output:
Adjusting posture…
Round black zafu
LocalJumpError: unexpected return

今何があったの?zafu_factory メソッドが作成し、暗黙的に proc を返しました。その後、proc は medicate メソッドによって呼び出され、proc 内の return ステートメントに到達すると、それが定義されたコンテキスト (zafu_factory メソッド) から戻ろうとしました。ただし、zafu_factory は既に proc を返しているため、メソッドは呼び出されるたびに 1 回しか返せません。つまり、プロシージャが呼び出されて 2 回目に返そうとしたときに、zafu_factory メソッドが既に返っていたため、例外がスローされました。

Procs と Lambdas: Closures in Rubyに関するこのブログ投稿で詳細を参照してください。

于 2016-05-17T22:10:41.480 に答える