2010-12-06 22 views
9

Tengo una situación en la que tengo una aplicación y se asigna a un directorio que necesito procesar en un archivo zip. El mapeo es bastante simple:Constantes hash en Perl

CWA => "Financial", 
PIP => "", 
IFA => "IFA", 
VDX => "Financial, 

Es decir, si el nombre del archivo comienza con CWA, sé el directorio Tengo que munge está bajo Financial. Si el nombre del archivo comienza con IFA, sé que el nombre del directorio es IFA. Me gustaría configurar esto como un hash (bastante fácil), pero dado que estos valores realmente no cambian, me gustaría configurar este mapeo key => value como una constante hash.

No creo que esto sea posible, así que me gustaría hacer la próxima mejor opción. ¿Qué sería eso? O bien, ¿puede configurar una constante hash?

Estoy pensando en escribir una subrutina donde pasa un parámetro y devuelve el valor correcto. Después de todo, es realmente la forma en que funcionan las constantes, y garantizaría que las relaciones entre las claves y los valores no cambien a lo largo del programa.

O, simplemente puedo declarar la relación clave => valor al comienzo de mi programa y espero que los pares clave => valor no sean modificados por algo. Esto sería más fácil de leer y más fácil de modificar si es necesario, ya que está en la parte superior de mi código fuente.

¿Cuál es la mejor forma de implementar una constante de clave => valor?

Respuesta

9
  1. Simplemente use un hash nombrado. Lo más probable es que nada salga mal.

  2. Use Readonly. Esto hace que se acceda a un hash al igual que cualquier otro hash, pero no se puede modificar a menos que alguien comience a hurgar en el interior de perl. Como se indica en sus documentos, es lento en comparación con un acceso variable regular, pero es muy poco probable que sea lo suficientemente lento como para importarle.

  3. Ocultar el hash en una subrutina.

.

sub get_directory_for_prefix { 
    my ($prefix) = @_; 
    my %map = (
     CWA => "Financial", 
     PIP => "", 
     IFA => "IFA", 
     VDX => "Financial", 

    ); 
    return $map{$prefix}; 
} 

o incluso

sub get_directory_for_prefix { 
    {CWA=>"Financial",PIP=>"",IFA=>"IFA",VOX=>"Financial"}->{shift()}; 
}; 
+0

mejor definir el mapa de mi% fuera de la función, justo por encima (y la función en un módulo separado al código de llamada, para que mi variable esté oculta). Esto evita una reinicialización innecesaria del hash cada vez que llama a la función. – ijw

+0

Este es un buen punto. O bien, en 5.10+, use 'state', que proporciona el mejor ocultamiento pero que solo se inicializa una vez. – hobbs

+0

El segundo funciona, pero tenía que hacer {+ shift}. De lo contrario, tomó {shift} como el índice en sí. –

7

Puede utilizar Const::Fast.

use Const::Fast; 
const my %hash = (
    CWA => "Financial", 
    PIP => "", 
    IFA => "IFA", 
    VDX => "Financial", 
); 
+4

Agradecimientos para Const :: Fast: "La interfaz para este módulo está inspirada en Readonly de Eric Roode. La implementación está inspirada en hacer todo lo contrario, Readonly lo hace". –

2

Aquí lo que finalmente se hizo después de algunas sugerencias:

{ 
    my %appHash = (
     CWA => "Financial", 
     PIP => "", 
     FIA => "FIA", 
     VDX => "Financial", 
    ); 

    sub appDir { 
     return $appHash{+shift}; 
    } 
} 

Al poner el %appHash en su propio bloque, no puede hacer referencia a ese resumen en el resto de mi código. Sin embargo, la subrutina appDir está en el mismo bloque y puede hacer referencia a ella. Y, como las subrutinas son de todo el paquete, puedo acceder a esa subrutina en mi código. Por lo tanto, puedo acceder a los valores de %appHash, pero no puedo cambiarlos.

use strict; 
use warnings; 
{ 
    my %appHash = (
     CWA => "Financial", 
     PIP => "", 
     FIA => "FIA", 
     VDX => "Financial", 
    ); 

    sub appDir { 
     return $appHash{+shift}; 
    } 
} 

{ 
    ### WARNING. 
    ### this code is a counter example to show that %appHash 
    ### is not available in this scope. 
    ### Do not use this code. 
    ### Disabling strictures and warnings in this block only. 

    no strict; 
    no warnings; # Danger Will Robinson! 
    # disable explicit package name error because %appHash is not defined in this scope. 
    # disable warnings related to 1) main::appHash and 2) uninitialized value of $appHash{"CWA"} 

    print "The directory for CWA is " . $appHash{CWA} . "\n"; #Prints nothing 
} 
print "The directory for CWA is " . appDir("CWA") . "\n"; #Prints Financial 

my %appHash; 
$appHash{CWA} = "FOO FOO FOO!"; 

print "The directory for CWA is " . $appHash{CWA} . "\n"; #Prints FOO FOO FOO! 
print "The directory for CWA is " . appDir("CWA") . "\n"; #Still prints Financial 

¡Neat!

Gracias iwj y hobbs

+0

¿Por qué debería desactivar estrictas y advertencias? O_o – antred

+0

@antred, con el estricto y las advertencias habilitadas, el primer ejemplo '$ appHash {CWA}' (contador) no se habría compilado. – spazm

+0

editado para deshabilitar restricciones y advertencias en un ámbito más pequeño. Y agregó una gran advertencia para responder el comentario sarcástico de @antred "O_o" – spazm

1

Alternativelly, si no se desea utilizar bloques que aún se podía utilizar constante:

use strict; 
use warnings; 

use constant CONSHASH => sub {{ 
    foo1 => 'bar1', 
    foo2 => 'bar2', 
    foo3 => 'bar3', 
}->{ +shift }}; 

print CONSHASH->('foo1') . "\n"; 
print CONSHASH->('foo2') . "\n"; 
print CONSHASH->('foo3') . "\n"; 
Cuestiones relacionadas