2009-12-03 23 views
7

Ecco cosa mi piacerebbe realizzare:Come potrei ridefinire una subroutine e mantenere quella precedente?

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" 

ho pensato che salvando il simbolo per first, sarei in grado di chiamare in seguito la subroutine originale (sotto il nome original_first) e di essere anche in grado per chiamare first e ottenere quello ridefinito. Tuttavia, se chiamo lo original_first, ottengo ancora il messaggio "questo viene prima ridefinito". Cosa devo fare per farlo funzionare?

risposta

9

Questo dovrebbe funzionare come ci si aspetta:

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

*original_first = \&first; 

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

È possibile, quando si ridefinisce il simbolo 'first', per influenzare solo la parte del codice? – Geo

+5

un assegnamento di un coderef (generato da sub {...}) a un typeglob sostituirà solo la voce CODE nel glob. qualsiasi altro tipo di dati nel glob non cambierà –

+4

Puoi anche usare 'local * first = sub {...};' per sostituire la funzione solo all'interno di un blocco specifico. –

9

nel codice, Perl interpreta entrambe le dichiarazioni sub simili a questo:

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

in modo che entrambi le assegnazioni per &first finiscono accadendo prima di salvare la copia e chiamando la routine. la correzione è quello di rendere la seconda dichiarazione in un incarico di esecuzione:

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

Bella spiegazione. Grazie! – Geo

+0

citazione necessaria per il comportamento 'sub {}' -> 'BEGIN {* ...}' che descrivi. – Ether

+0

sto deducendo quanto sopra dalla seguente spiegazione da perlmod: le definizioni di subroutine (e le dichiarazioni, per quella materia) non devono necessariamente essere situate nel pacchetto di cui occupano la tabella dei simboli. È possibile definire una subroutine all'esterno del pacchetto specificando esplicitamente il nome della subroutine: 1. package main; 2. sub Un_Pacchetto :: pippo {...} # & foo definito Un_Pacchetto Questa è solo una scorciatoia per un incarico typeglob in fase di compilazione: 1. begin {* Un_Pacchetto :: foo = sub {... }} –

1

vedere il modulo Hook::LexWrap, che può gestire tutto questo per voi. Se non vuoi usare il modulo, guarda la fonte, che ti mostra esattamente come farlo.