2013-03-22 7 views
11

Ich habe eine Menge Probleme zu verstehen, wie return funktioniert in Blöcken, Procs und Lambdas.Return-Anweisungen in Procs, Lambdas und Blöcke

Zum Beispiel im folgenden Fall, warum funktioniert batman_ironman_proc arbeiten, während batman_yield einen Fehler werfen?

def batman_ironman_proc 
    victor = Proc.new { return "Batman will win!" } 
    victor.call 
    "Iron Man will win!" 
end 

def batman_yield 
    yield 
    "Iron man will win!" 
end 

victor = Proc.new { return "Batman will win!" } 

puts batman_ironman_proc 
#batman_yield(&victor) === This code throws an error. 
+0

möglich Duplikat von [Verwenden von 'Rückkehr' in einem Ruby-Block] (http://stackoverflow.com/questions/2325471/using-return-in-a-ruby-block) – mgibsonbr

+1

Hier: http: // stackoverflow. com/questions/1435743/why-does-explizite-return-make-a-Differenz-in-a-proc – fmendez

+0

Ich weiß, dass Sie das von Codeacademy lernen. Ich habe dieselben Zweifel. Es ist ein anständiges Einführungs-Tutorial, aber Sie müssen Google viel suchen, um das Tutorial zu verstehen. –

Antwort

9

Wie one answer in der verknüpften Frage zeigt:

Das return Stichwort immer kehrt aus dem Verfahren oder Lambda im aktuellen Kontext. In Blöcken wird es von der Methode, in der der Verschluss definiert wurde, zurückgegeben. Es kann nicht veranlasst werden, von Aufruf Methode oder Lambda zurückzukehren.

Ihr erstes Beispiel war erfolgreich, weil Sie victor in der gleichen Funktion definiert Sie zurückkehren wollte, so ein return legal war in diesem Zusammenhang. In Ihrem zweiten Beispiel wurde victor in der obersten Ebene definiert. Der Effekt dieser return würde dann nicht sein, um von batman_yield (die aufrufende Methode) zurückzukehren, aber [wenn es gültig war] von der obersten Ebene selbst zurückzukehren (wo die Proc definiert wurde).

Erläuterung: während Sie auf den Rückgabewert eines Blocks zugreifen können (zB "Der Wert des letzten im Block ausgewerteten Ausdrucks wird als Wert der Ausbeute an die Methode zurückgegeben" - gemäß Ihrem Kommentar) , Sie kann nicht verwenden Sie das return Schlüsselwort, aus dem oben genannten Grund. Beispiel:

def batman_yield 
    value = yield 
    return value 
    "Iron man will win!" 
end 

victor = Proc.new { return "Batman will win!" } 
victor2 = Proc.new { "Batman will win!" } 

#batman_yield(&victor) === This code throws an error. 
puts batman_yield(&victor2) # This code works fine. 
+1

vorausgesetzt, dass dies der Fall ist, wie verwendet Methode wie find, die Blöcke mit logischen Tests akzeptieren, die Ergebnisse dieser logischen Tests? (Beispiel: [1,2,3,4,8,10] .find {| num * num> 24}) – voltair

+0

@ user1419674 siehe die aktualisierte Antwort. Genauso, wie Ihr Beispielcode 'return' nicht verwendet hat, müssen Sie ihn auch nicht verwenden, um auf die Auswertung des Blocks zuzugreifen. Sie können einfach den Rückgabewert von 'call' verwenden, ihn direkt verwenden (wie in meinem Beispielcode) oder einer Variablen zuweisen (zB:" value = block.call ") – mgibsonbr

+0

Das ist mir ziemlich fremd, aber ich Ich glaube, dieser Link liefert eine Antwort auf die Frage. [link] http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_containers.html Es sagt tatsächlich, dass der Ertrag einen Rückgabewert liefern kann. Was mich so merkwürdig findet, ist, dass in diesem Fall eine explizite Rückkehr und eine implizite Rückkehr zu unterschiedlichen Ergebnissen innerhalb des Blocks führen. – voltair

0

Ich komme aus einem C Hintergrund und die Art, wie ich es erklären würde, wenn Sie eine Funktion, die Sie einen Rückkehrbefehl Nummer gesetzt anrufen und ein Register, das den zurückgegebenen Wert speichert. Im Falle von proc und block wird die Rückgabeanweisung nicht gesetzt, da sie inline oder im selben Bereich aufgerufen werden, aber sie können immer noch einen zurückgegebenen Wert zurückgeben, da dies unabhängige Funktionen sind. Ohne einen Return-Befehl, der gesetzt wird, geben proc/block uns einen LocalJumpError, während wir, wenn wir nur einen Wert zurückgeben wollen, das in Ordnung ist.