2009-12-03 11 views
7

Esto es lo que me gustaría lograr:¿Cómo podría redefinir una subrutina y conservar también la anterior?

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" 

pensé que guardando el símbolo de first, me gustaría ser capaz de llamar a la subrutina tarde originales (bajo el nombre original_first) y también poder para llamar al first, y obtener el redefinido. Sin embargo, si llamo al original_first, sigo teniendo el mensaje "esto primero se redefine". ¿Qué tengo que hacer para que esto funcione?

Respuesta

9

Esto debería funcionar como se espera:

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

*original_first = \&first; 

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

¿Es posible, cuando redefine el símbolo 'first', afectar solo a la parte del código? – Geo

+5

una asignación de un coderef (generado por sub {...}) a un typeglob solo reemplazará la entrada CODE en el glob. cualquier otro tipo de datos en el globo no cambiará –

+4

También puede usar 'local * first = sub {...};' para reemplazar la función dentro de un bloque específico solamente. –

9

en su código, Perl interpreta ambas declaraciones sub similares a esta:

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

por lo tanto las asignaciones a &first a poco pasará antes de guardar la copia y llamando a las rutinas. la solución es hacer que la segunda declaración en una asignación de tiempo de ejecución:

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

Buena explicación. ¡Gracias! – Geo

+0

citation needed para el comportamiento 'sub {}' -> 'BEGIN {* ...}' que describes. – Ether

+0

infiero lo anterior de la siguiente explicación de perlmod: las definiciones de subrutina (y las declaraciones, para el caso) no necesariamente tienen que estar situadas en el paquete cuya tabla de símbolos ocupan. Puede definir una subrutina fuera de su paquete calificando explícitamente el nombre de la subrutina: 1. package main; 2. sub Some_package :: foo {...} # & foo definido en Some_package Esto es sólo una forma abreviada de una asignación typeglob en tiempo de compilación: 1. begin {* Some_package :: foo = {sub ... }} –

1

Véase el módulo Hook::LexWrap, que puede manejar todo eso para usted. Si no desea utilizar el módulo, simplemente mire la fuente, que le muestra exactamente cómo hacerlo.

Cuestiones relacionadas