2013-03-22 9 views
11

Sto avendo un sacco di problemi a capire come funziona return in blocchi, proc e lambda.Restituire le istruzioni all'interno di procs, lambda e blocchi

Ad esempio, nel seguente caso, perché funziona batman_ironman_proc, mentre batman_yield genera un errore?

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

possibile duplicato di [Utilizzo 'return' in un blocco Ruby] (http://stackoverflow.com/questions/2325471/using-return-in-a-ruby-block) – mgibsonbr

+1

Qui: http: // stackoverflow. it/questions/1435743/why-does-explicit-return-make-a-difference-in-a-proc – fmendez

+0

So che stai imparando questo da codeacademy. Ho gli stessi dubbi. È un tutorial introduttivo decente, ma devi cercare su google un sacco per essere in grado di capire il tutorial. –

risposta

9

Come one answer nella questione legata mostra:

Le parole chiave returnsempre ritorna dal metodo o lambda nel contesto attuale. Nei blocchi, verrà restituito dal metodo in cui la chiusura era definita. Non è possibile effettuare il reso dallo chiamando il metodo o lambda.

Il tuo primo esempio ha avuto successo perché è stata definita victor nella stessa funzione che si voleva tornare da, quindi un return era legale in quel contesto. Nel secondo esempio, victor è stato definito nel livello principale. L'effetto di tale return, quindi, sarebbe non da restituire da batman_yield (il metodo di chiamata), ma [se fosse valido] per tornare dal livello superiore stesso (in cui è stato definito Proc).

Chiarificazione: mentre è possibile accedere al valore di ritorno di un blocco (ad es. "Il valore dell'ultima espressione valutata nel blocco viene restituito al metodo come valore del rendimento" - come da commento) , non è possibile utilizzare la parola chiave return, per il motivo indicato sopra. Esempio:

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

dato che questo è il caso, in che modo metodi come find, che accettano blocchi con test logici, usano i risultati di quei test logici? (esempio: [1,2,3,4,8,10] .find {| num | num * num> 24}) – voltair

+0

@ user1419674 vedere la risposta aggiornata. Nello stesso modo in cui il tuo codice di esempio non usa 'return', non devi usarlo neanche per accedere alla valutazione del blocco. Puoi semplicemente usare il valore di ritorno da 'call', usandolo direttamente (come nel mio codice di esempio) o assegnandolo a una variabile (es .:' value = block.call') – mgibsonbr

+0

Questo è piuttosto strano per me, ma io credo che questo link fornisca una risposta alla domanda. [link] http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_containers.html In realtà dice che yield può fornire un valore di ritorno. Ciò che mi sembra così strano è che in questo caso sembrerebbe che un ritorno esplicito e un ritorno implicito producano risultati diversi all'interno del blocco. – voltair

0

io vengo da un background C e il modo in cui vorrei spiegarlo è quando si chiama una funzione di impostare un numero di istruzioni di ritorno e un registro che memorizza il valore restituito. In caso di proc e block l'istruzione return non è impostata perché sono inline o chiamate nello stesso scope ma possono comunque restituire un valore restituito perché queste sono funzionalità indipendenti. Quindi, senza un'istruzione di ritorno impostata, proc/block ci sta dando un LocalJumpError mentre se vogliamo solo restituire un valore va bene.

Problemi correlati