Frage

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" 

Ich dachte, die return Stichwort wurde in Ruby optional und dass Sie immer returning, ob Sie es verlangen oder nicht.Da finde ich es verwunderlich, dass foo und bar unterschiedliche output-bestimmt durch die Tatsache, dass foo enthält eine explizite return in Proc f.

Weiß jemand, warum dies der Fall ist?

War es hilfreich?

Lösung

Ruby hat drei Konstrukte:

  1. Ein block ist kein Objekt und erstellt von { ... } oder do ... end.
  2. Ein proc ist ein Proc Objekt erstellt von Proc.new oder proc.
  3. Ein lambda ist ein Proc erstellt von lambda (oder proc in Ruby 1.8).

Ruby hat drei Schlüsselwörter, die Rückkehr von etwas:

  1. return beendet die Methode oder ein lambda-Ausdruck es ist.
  2. next beendet den block, proc, oder lambda-Ausdruck es ist.
  3. break beendet die Methode ergab, dass der block aufgerufen oder das proc-oder lambda-Ausdruck es ist.

In lambdas, return verhält sich wie next, aus welchem Grund auch immer. next und break benannt sind wie Sie sind, weil Sie werden am häufigsten verwendet, mit Methoden wie each, wo die Beendigung der block wird verursachen die iteration fortsetzen mit der weiter element der Sammlung und beenden each führen, dass Sie Pause aus der Schleife.


Wenn Sie return innerhalb der definition von foo, Sie wird von foo, auch wenn es in einem block oder einer proc.Die Rückkehr aus einem block, den Sie verwenden können die next Stichwort statt.

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"

Andere Tipps

Dies ist die Semantik für Procs; es ist nicht unbedingt die Semantik für alle Blöcke. Ich bin damit einverstanden dies ein wenig verwirrend ist. Es ist dort für zusätzliche Flexibilität (und vielleicht teilweise verursacht Rubin keine spec mit Ausnahme deren Umsetzung hat).

Das Verhalten wird in der Proc Implementierung definiert. Lambdas verhalten sich anders, wenn Sie also Ihre returns möchten nicht verlassen aus dem einschließenden Verfahren, verwenden lambdas . Oder lassen Sie das return Stichwort aus Ihrem Proc.

Eine tiefe Untersuchung von Rubys Schließungen ist hier . Es ist ein fantastisches Exposé.

So:

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) 

Denken auf diese Weise davon: Proc.new nur einen Block von Code erstellen, der Teil der Aufruffunktion ist. proc / Lambda schafft eine anonyme Funktion, die besonderen Bindungen hat. Ein wenig Codebeispiele helfen:

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

entspricht

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

  return "return from foo" 
end

so ist es klar, dass die Rückkehr kehrt gerade von der Funktion ‚foo‘

Im Gegensatz:

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

entspricht (die Bindungen zu ignorieren, da in diesem Beispiel nicht verwendet):

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

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

, die als klar wird bestätigt von foo ist und stattdessen auf die nächste Anweisung fortgesetzt werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top