I have a situation where I have an application and it maps to a directory I need to process in a zipfile. The mapping is quite simple:
CWA => "Financial",
PIP => "",
IFA => "IFA",
VDX => "Financial,
That is, if the name of the file begins with CWA
, I know the directory I have to munge is under Financial
. If the file name begins with a IFA
, I know the directory name is IFA
. I'd like to set this up as a hash (easy enough), but since these values don't really change, I'd like to setup this key => value mapping as a hash constant.
I don't believe this is possible, so I'd like to do the next best thing. What would that be? Or, can you setup a hash constant?
I'm thinking of writing a subroutine where you pass a parameter and it returns the correct value. After all, it's really the way constants themselves work, and it'd guarantee that the relationships between the keys and values don't change through out the program.
Or, I can simply declare the key => value relationship in the beginning of my program and hope that the key => value pairs aren't modified by something. This would be easier to read, and easier to modify if you have to since it's on the very top of my source code.
What's the best way to implement a key 开发者_StackOverflow=> value constant?
You can use Const::Fast
.
use Const::Fast;
const my %hash = (
CWA => "Financial",
PIP => "",
IFA => "IFA",
VDX => "Financial",
);
Just use a named hash. Most likely, nothing will go wrong.
Use Readonly. This makes a hash that is accessed like any other hash, but can't be modified unless someone starts mucking around in the perl internals. As stated in its docs, it's slow compared to a regular variable access, but it's very unlikely to be slow enough to matter for you.
Hide the hash in a subroutine.
.
sub get_directory_for_prefix {
my ($prefix) = @_;
my %map = (
CWA => "Financial",
PIP => "",
IFA => "IFA",
VDX => "Financial",
);
return $map{$prefix};
}
or even
sub get_directory_for_prefix {
{CWA=>"Financial",PIP=>"",IFA=>"IFA",VOX=>"Financial"}->{shift()};
};
Alternativelly, if you don't want to use blocks you could still use constant:
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";
Here what I finally did following a few suggestions:
{
my %appHash = (
CWA => "Financial",
PIP => "",
FIA => "FIA",
VDX => "Financial",
);
sub appDir {
return $appHash{+shift};
}
}
By putting the %appHash
in its own block, I can't reference that hash in the rest of my code. However, the appDir
subroutine is in the same block and can reference it. And, because Subroutines are package wide, I can access that subroutine in my code. Therefore, I can access the values of %appHash
, but I cannot change them.
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!
Thanks iwj and hobbs
精彩评论