Perché la dichiarazione di pausa in Ruby si comporta in modo diverso quando si utilizza Proc.new v. Il segno AmperSand?
-
29-10-2019 - |
Domanda
La dichiarazione di pausa per i blocchi (secondo Il linguaggio di programmazione Ruby) è definito come segue:
Fa tornare il blocco al suo iteratore e all'iteratore di tornare al metodo che lo ha invocato.
Pertanto, quando viene eseguito il seguente codice, si traduce in un jumperror locale.
def test
puts "entering test method"
proc = Proc.new { puts "entering proc"; break }
proc.call # LocalJumpError: iterator has already returned
puts "exiting test method"
end
test
Mentre il seguente codice non Lancia un jumperror locale. Cosa c'è di speciale nel segno AmperSand? Il segno AmperSand non usa implicitamente Proc.New?
def iterator(&proc)
puts "entering iterator"
proc.call # invoke the proc
puts "exiting iterator" # Never executed if the proc breaks
end
def test
iterator { puts "entering proc"; break }
end
test
In altre parole, ho letto il segno AmperSand come mezzo per allineare la chiamata del Proc.New. A quel punto il comportamento dovrebbe essere lo stesso del primo frammento di codice.
def iterator (p = Proc.new { puts "entering proc"; break})
...
end
Disclaimer: Sono Newb che impara la lingua (Ruby 1.9.2) e quindi apprezzerò i riferimenti e una sinossi dettagliata.
Soluzione
break
fa il blocco e il chiamante del ritorno del blocco. Nel seguente codice:
proc = Proc.new { break }
Il "chiamante" del blocco che viene convertito in un oggetto Proc è Proc.New. break
dovrebbe far riportare il chiamante del blocco, ma Proc.new è già tornato.
In questo codice:
def iterator(&b); b.call; end
iterator { break }
Il chiamante del blocco è iterator
, così fa iterator
Restituzione.
Altri suggerimenti
Ecco il Rispondere.
AmperSand viene utilizzato per convertire un Proc in un blocco e un blocco in un proc.
Ho cambiato l'esempio in modo da relazionare al tuo caso:
def run_my_code(&my_code)
puts 'before proc'
my_code.call
puts 'after proc'
end
run_my_code { puts "passing a block, accepting a proc"; break}
=> before proc
passing a block, accepting a proc
Come puoi vedere, non ha raggiunto il "After Proc"
def run_my_code
yield
end
my_proc = Proc.new { puts "passing a proc instead of block"; break}
run_my_code &my_proc
=> passing a proc instead of block
LocalJumpError: break from proc-closure
from (pry):75:in `block in <main>'
Nel tuo secondo esempio hai un proc di risultato, il proc si interrompe da iterator
e ritorna a test
funzione.
def iterator(&proc)
puts 'entering iterator'
proc.call
puts 'exiting iterator'
end
def test
puts 'before test'
iterator { puts 'entering proc'; break }
puts 'after test'
end
=>before test
entering iterator
entering proc
after test
Ha a che fare con la differenza tra blocchi, proc e lambdas - e i rispettivi ambiti.
Ho scritto un post su di esso nel 2009 che potresti trovare utile: http://www.leonardobolges.com/writings/2009/07/22/procs-lambdas-blocks-whats-the-diffference/
Spero che sia di aiuto.