2010-12-06 5 views
1

Je lis this blog et suis tombé sur le code suivantException efface la trace de la pile de quoi?

RunAgain = Class.new(Exception) 
def fib(i, n = 1, result = 0) 
    if i == -1 
    result 
    else 
    raise RunAgain 
    end 
rescue RunAgain 
    i, n, result = i - 1, n + result, n 
    retry 
end 

Il semble que pour le code ci-dessus fonctionne, une fois exception est levée alors rubis doit être Clearing toute trace de la pile et le remplacement que la pile d'exception.

Est-ce que je comprends bien?

Répondre

2

Le fonctionnement de ce code n'a en fait rien à voir avec la pile. Il y a deux entrées sur la pile tout le temps, fib et l'appelant de fib. L'augmentation de l'exception est une sorte de harcèlement à votre question - il ne sert à rien dans cet exemple autre que la démonstration du comportement de retry.

Ruby retry est similaire à d'autres mots-clés de contrôle comme next et break et redo. Le mot clé redo signifie essayer de nouveau la boucle ou le bloc en cours. Le mot clé retry fonctionne à l'intérieur d'un secours pour réessayer le bloc en cours qui a déclenché l'exception.

Alors qu'est-ce qui se passe ici est quelques valeurs initiales sont définies pour i, n et result, un boîtier de base est vérifiée (i == -1), et si non satisfait, nous mettons à jour les valeurs et essayer de nouveau à partir du haut. Notez que puisque ces valeurs sont des paramètres de méthode et non des variables locales, elles ne sont pas réinitialisées. Attention, puisque Fibonacci est un exemple très courant (et très médiocre) de récursion, ne pas confondre cela avec un algorithme récursif. Le RunAgain déclenche et sauve des fonctions comme une boucle, sans rappeler la fonction ou modifier la pile d'appel.

Votre code exemple est équivalent à

def fib(i) 
    n, result = 1, 0 
    (i+1).times { n, result = n + result, n } 
    result 
end 

note dans les deux cas, i est juste un compteur et rien de plus. Nous exécutons le code i+1 fois. Notez également que le besoin typique d'une variable temporaire pour échanger des valeurs est remplacé par la construction d'assignation multiple de ruby.

+0

Si je demande fibonacci pour une grande valeur, il y aura 10 millions d'exceptions soulevées. Si toutes ces informations d'exceptions sont conservées sur la pile, l'erreur de trace de la pile sera éventuellement levée. D'où ma question était est l'information de trace de pile retirée de la pile quand la prochaine exception arrive. –

+1

@Nadal, voir la deuxième phrase de ma réponse. "Il y a deux entrées sur la pile tout le temps." Votre exemple a une récursivité nulle et les exceptions déclenchées n'ont aucun impact sur la pile. –

Questions connexes