web-dev-qa-db-ja.com

明示的な返品がProcに違いをもたらすのはなぜですか?

def foo
  f = Proc.new { return "return from foo from inside proc" }
  f.call # control leaves foo here
  return "return from foo" 
end

def bar
  b = Proc.new { "return from bar from inside proc" }
  b.call # control leaves bar here
  return "return from bar" 
end

puts foo # prints "return from foo from inside proc" 
puts bar # prints "return from bar" 

returnキーワードはRubyでオプションであり、リクエストするかどうかに関係なく、常にreturningであると思いました。それを考えると、foobarの出力が異なるという事実によって決定されるのは驚くべきことです。 fooには、Proc fに明示的なreturnが含まれています。

なぜこれが当てはまるのか誰かが知っていますか?

51
uzo

これはProcsのセマンティクスです。必ずしもすべてのブロックのセマンティクスであるとは限りません。これは少し紛らわしいことに同意します。それは追加の柔軟性のためにあります(そしておそらく部分的にRubyはその実装を除いて仕様がありません)。

動作はProc実装で定義されます。 Lambdasの動作が異なるため、returnsを囲んでいるメソッドから終了しないようにする場合は、lambdas。または、returnからProcキーワードを省略します。

Rubyのクロージャの詳細な調査 ここにあります 。それは素晴らしい博覧会です。

そう:

def foo   
  f = Proc.new {
    p2 = Proc.new { return "inner proc"};
    p2.call
    return "proc"
  }
  f.call
  return "foo"
end

def foo2
  result = Proc.new{"proc"}.call
  "foo2 (proc result is: #{result})"
end

def bar
  l = lambda { return "lambda" }
  result = l.call
  return "bar (lambda result is: #{result})"
end

puts foo
# inner proc
puts foo2
# foo (proc result is: proc) 
puts bar
# bar (lambda result is: lambda) 
12
Sam Saffron

このように考えてください。Proc.newは、呼び出し元の関数の一部であるコードのブロックを作成するだけです。 proc/lambdaは、特別なバインディングを持つ無名関数を作成します。小さなコード例が役立ちます:

def foo
  f = Proc.new { return "return from foo from inside Proc.new" }
  f.call # control leaves foo here
  return "return from foo" 
end

と同等です

def foo
  begin
    return "return from foo from inside begin/end" }
  end

  return "return from foo" 
end

したがって、戻り値が関数 'foo'から戻ることは明らかです。

対照的に:

def foo
  f = proc { return "return from foo from inside proc" }
  f.call # control stasy in foo here
  return "return from foo" 
end

(この例では使用されていないため、バインディングを無視します)と同等です。

def unonymous_proc
  return "return from foo from inside proc"
end

def foo
  unonymous_proc()
  return "return from foo" 
end

これは明らかにfooから戻らず、代わりに次のステートメントに進みます。

7
Vitaly Kushner