2009-12-03 28 views
7

Voici ce que je voudrais obtenir:Comment pourrais-je redéfinir un sous-programme et conserver l'ancien aussi?

sub first { 
    print "this is original first"; 
} 

*original_first = \&first; 

sub first { 
    print "this is first redefined"; 
} 

original_first(); # i expect this to print "this is original first" 
first() # i expect this to print "this is first redefined" 

Je pensais qu'en sauvant le symbole de first, je serais en mesure d'appeler plus tard, le sous-programme d'origine (sous le nom original_first) et d'être également en mesure appeler first, et obtenir celui redéfini. Cependant, si j'appelle le original_first, je reçois toujours le "ceci est d'abord redéfini". Que dois-je faire pour que cela fonctionne?

Répondre

9

Cela devrait fonctionner comme prévu:

sub first { 
    print "this is original first"; 
} 

*original_first = \&first; 

*first = sub { 
    print "this is first redefined"; 
}; 
+0

Est-il possible, lorsque vous redéfinissez le symbole «first», d'affecter uniquement la partie code? – Geo

+5

une affectation d'un coderef (généré par sub {...}) à un typeglob ne remplacera que l'entrée CODE dans le glob. tout autre type de données dans le glob ne changera pas –

+4

Vous pouvez également utiliser 'local * first = sub {...};' pour remplacer la fonction dans un bloc spécifique seulement. –

9

dans votre code, Perl interprète les deux déclarations sous similaires à ceci:

BEGIN { 
    *first = sub { ... } 
} 

afin que les deux missions à &first finissent passe avant d'enregistrer la copie et en appelant les routines. la solution est de faire la deuxième déclaration dans une mission d'exécution:

sub first { 
    print "this is original first"; 
} 

*original_first = \&first; 

*first = sub {print "this is first redefined"}; 

original_first(); # prints "this is original first" 
first();   # prints "this is first redefined" 
+0

Belle explication. Merci! – Geo

+0

citation nécessaire pour le comportement 'sub {}' -> 'BEGIN {* ...}' que vous décrivez. – Ether

+0

Je déduis de ce qui précède de l'explication suivante de perlmod: Les définitions de sous-routine (et les déclarations, d'ailleurs) ne doivent pas nécessairement être situées dans le paquet dont elles occupent la table de symboles. Vous pouvez définir un sous-programme en dehors de son paquet en qualifiant explicitement le nom du sous-programme: 1. paquet principal; 2. sous Some_package :: foo {...} # & foo définie dans Some_package Ceci est juste un raccourci pour une affectation de typeglob au moment de la compilation: 1. begin {* Some_package :: foo = sub {... }} –

1

Voir le module Hook::LexWrap, qui peut gérer tout cela pour vous. Si vous ne voulez pas utiliser le module, regardez simplement la source, qui vous montre exactement comment le faire.