Pourquoi l'instruction break dans ruby se comporte-t-elle différemment lors de l'utilisation de Proc.new v. Le signe esperluette?
-
29-10-2019 - |
Question
L'instruction break pour les blocs (selon " Le programme est défini comme suit "
cela fait revenir le bloc à son itérateur et l'itérateur à retourner à la méthode qui l'a appelé.
Par conséquent, lorsque le code suivant est exécuté, il en résulte une LocalJumpError.
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
Bien que le code suivant ne lève pas une erreur LocalJumpError. Quelle est la particularité du signe esperluette? L'esperluette n'utilise-t-elle pas implicitement 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
En d'autres termes, je lis le signe esperluette comme un moyen d'insérer l'appel Proc.new. À ce stade, le comportement doit être exactement le même que celui du premier extrait de code.
def iterator (p = Proc.new { puts "entering proc"; break})
...
end
La solution
break
rend le bloc et l ' appelant du bloc de retour.Dans le code suivant:
proc = Proc.new { break }
L '"appelant" du bloc converti en objet Proc est Proc.new.break
est censé faire revenir l'appelant du bloc, mais Proc.new est déjà retourné.
Dans ce code:
def iterator(&b); b.call; end
iterator { break }
L'appelant du bloc est iterator
, donc il renvoie iterator
.
Autres conseils
Voici la réponse .
Ampersand est utilisé pour convertir un proc en bloc et un bloc en proc.
J'ai changé l'exemple pour le mettre en relation avec votre cas:
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
Comme vous pouvez le voir, il n'a pas atteint le "proc après"
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>'
Dans votre deuxième exemple, vous avez un proc in result, le proc rompt avec iterator
et retourne à la fonction test
.
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
Cela a à voir avec la différence entre les blocs, les procs et les lambdas - et leurs portées respectives.
J'ai écrit un article à ce sujet en 2009 que vous pourriez trouver utile: http://www.leonardoborges.com/writings/2009/07/22/procs-lambdas-blocks-whats-the-difference/
J'espère que cela vous aidera.