57
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" 

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

なぜこれが事実なのか誰にも分かりますか?

4

3 に答える 3

99

Ruby has three constructs:

  1. A block is not an object and is created by { ... } or do ... end.
  2. A proc is a Proc object created by Proc.new or proc.
  3. A lambda is a Proc created by lambda (or proc in Ruby 1.8).

Ruby has three keywords that return from something:

  1. return terminates the method or lambda it is in.
  2. next terminates the block, proc, or lambda it is in.
  3. breakブロックを明け渡したメソッド、またはそれが含まれる proc またはラムダを呼び出したメソッドを終了します。

ラムダでは、何らかの理由で のreturnように動作します。ブロックを終了すると、コレクションの次の要素で反復が再開され、終了するとループから抜け出しますnextnextbreakeacheach


returnの定義内で 使用すると、ブロックまたはプロシージャ内であってもfooから戻ります。fooブロックから戻るには、next代わりにキーワードを使用できます。

def foo
  f = Proc.new { next "return from foo from inside proc" }
  f.call # control leaves foo here
  return "return from foo" 
end
puts foo # prints "return from foo"
于 2009-09-16T22:13:16.030 に答える
16

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

動作はProc実装で定義されます。Lambdasの動作は異なるため、returnsを囲んでいるメソッドから出たくない場合は、ラムダを使用します。returnまたは、からキーワードを省略しますProc

Rubysクロージャーの詳細な調査はこちらです。それは素晴らしい博覧会です。

それで:

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) 
于 2009-09-16T23:28:24.833 に答える
8

このように考えてください。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から戻らず、代わりに次のステートメントに進みます。

于 2009-09-17T18:29:38.090 に答える