Perché la dichiarazione di pausa in Ruby si comporta in modo diverso quando si utilizza Proc.new v. Il segno AmperSand?

StackOverflow https://stackoverflow.com/questions/8888958

  •  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.

È stato utile?

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top