2010-06-14 12 views
6

A veces necesito una función de utilidad útil, como List::Util::max en medio de un programa grande que hace muchas cosas. Así que si lo hagoImportación léxica de funciones útiles en un script grande

use List::Util 'max'; 

En la parte superior de mi programa, tengo que cargar con ese símbolo, contaminando toda mi espacio de nombres, aunque sólo lo necesito en una subrutina.

Así que he estado pensando en probar un modelo diferente, en su lugar:

use List::Util(); 

# a whole bunch of stuff later... 
sub blah { 
    List::Util->import('max'); 
    $blah = max @foobar; 
    ... 
} 

Hay dos problemas con esto, sin embargo. Por un lado, no se desimporta automáticamente al final del bloque (drat.) Tendría que deshacer todo con un unimport.

El otro problema es que aparentemente los prototipos no se aplican correctamente, así que tengo que decir max(@foobar) en lugar de la versión sin parntesis más bonita.

¿Hay una manera fácil de importar temporalmente símbolos para un bloque, lo que automagicamente hacer que desaparezcan al final del bloque, y lo que también prototipos manejar correctamente?

Respuesta

1

Puede localizar una entrada de tabla de símbolos:

use List::Util(); 

@y = qw(1 3 5 -9 4); 

sub max { # return maximum *absolute value* of list 
    my $max = abs(shift); 
    $max<abs($_) && ($max=$abs($_)) for @_; 
    return $max; 
} 

sub max2 { 
    local *max = *List::Util::max; 
    return max(@_); 
} 

print "My max:   ", max(@y), "\n"; # ==> 9 
print "List::Util::max ", max2(@y), "\n"; # ==> 5 
+3

Esto introducirá errores sutiles si cualquiera de los 'máximos' tiene un prototipo, ya que el efecto de eso se quemará en tiempo de compilación. En 'max2', se usa el prototipo de' main :: max', no el de 'List :: Util :: max'. De manera útil, debería recibir una advertencia sobre el prototipo de desajuste en la asignación. –

+0

@Eric Strom - Buen punto, eso apestaría. Use un nombre de subrutina 'local' con precaución. – mob

4

a hacer esto, es mucho mejor y más limpia:

package Foo; 
use strict; use warnings; 
use List::Util 'max'; 
use namespace::autoclean; 

# your method definitions here... 

namespace::autoclean voluntad es hecha "UNIMPORT" el símbolo después del ciclo de compilación del paquete. La llamada a ella en su método seguirá funcionando, pero no tiene contaminación del espacio de nombres (se elimina el símbolo *Foo::max) y se producirá un error al llamar al $obj->max().

Alternativamente, es posible que desee echar un vistazo a Lexical::Import (No sé nada al respecto, un irc birdie lo mencionó).

+0

Mientras 'espacio de nombres :: autoclean' es spiffy, no resuelve el problema principal que es que' max' todavía está allí en todo el paquete en lugar de limitada a un solo bloque, el cual es lo que realmente estoy tratando de lograr. Quiero que mis funciones de utilidad se comporten como variables léxicas. – friedo

+0

@friedo: ¿por qué es un problema que 'max' esté disponible para todo el paquete? Si la preocupación es la contaminación del espacio de nombres, de eso se ocupa este módulo. – Ether

+0

Tal vez quiero un * max * 'max * en otro lugar del paquete. – friedo

1

perlfunc implica que no MODULE debe hacer lo que quiera:

sub blah { 
    use List::Util qw(max); 
    say max @foobar; 
    no List::Util; 
} 

pero eso no funciona - al menos no para de lista: : Util. Creo que necesitaría definir un método unimport. Incluso entonces, no estoy seguro si podría tener un max desnudo en su módulo de llamadas diferentes definiciones.

+0

¿No se ejecutarían las líneas 'use' y' no' en un tiempo diferente (anterior) que el resto de la definición secundaria? – Ether

+0

Tanto 'use' como' no' ocurren en tiempo de compilación; se ejecutarían mientras se compilaba 'blah'. –

2

Si solo utiliza max en una subrutina, no la importaría en el espacio de nombre. Mi solución es

use List::Util; 
sub blah { 
    print List::Util::max(@list); 
} 
+0

Esto aún respeta los prototipos, por lo que puede omitir los corchetes: print List :: Util :: max @list; – dwarring

Cuestiones relacionadas