How would I create开发者_高级运维 a hash like the follow:
my %hash = (key1=>"Something", key2=>$hash{key1} . "Else");
Can this not be done while when I declare the hash? So far, the only thing I came up with was:
my %hash = (key1=>"Something");
$hash{key2} = $hash{key1} . "Else";
Why not use an intermediate variable?
my $common_value = 'Something';
my %some_hash = ( k1 => $common_value, k2 => $common_value.'Else' );
Update
kemp asked why we need an intermediate variable. I can interpret this question it two ways, I'll endeavor to answer both interpretations.
Why can't you do
my %hash = ( k1 => 'foo', k2 => $hash{k1}.'bar' );
?The right-hand side (rhs) of the expression is evaluated before the left-hand side (lhs). So, when the value for
k2
is determine, no assigment to%hash
has yet occurred. In fact,%hash
has not even been created and entered into the scratch pad yet. (%hash
is a lexical variable here, so it won't go into the symbol table.)Why use a variable rather than another method?
Well, there are many ways to initialize a hash with values like this. I would use an intermediate variable if I had a small number of related keys to initialize.
my $cv1 = sub_result() * 5; my $cv2 = "Number: $cv1"; my %h = ( k1 => $cv1, k2 => $cv2, k3 => "Numero: $cv1", k4 => "Big $cv2", k5 => "Round $cv2", k6 => "Whole $cv2", k7 => "-$cv1", );
However, if I had to build up many complicated values that depended on many different keys, I'd probably use a data driven approach to initialize the hash. The exact implementation would depend on details I don't have, but it might look something like this:
use Scalar::Util qw(reftype); my @init = ( [ key1 => $value ], [ key2 => \&make_a_value, 'key1' ], [ key3 => \&another_way, 'key2' ], ); my %h; for my $spec ( @init ) { my $key = shift @$spec; my $value = shift @$spec; my @args = @$spec; if( reftype $value eq reftype sub {} ) { $value = $value->( @h{ @args } ); } $h{$key} = $value; }
For any case where this question arrises, the choice as to what technique to use depends on many details that are special to that instance. So we are left with the necessity to make generic statements. Intermediate variables are one good way approach the OP's problem. Whether they should be used in his particular case, I can not say.
It cannot be done for 2 reasons:
At the time Perl processes
key2 => $hash{key1}
, it has not yet associated the memory allocated with key 1 with the hash name hash. In other words,$hash{key1}
does not point to the correct place in memory until afterkey2 => $hash{key1}
is already assigned.Previous reason didn't state the additional problem: you didn't yet place
%hash
into a symbol table by the time you processkey2 => $hash{key1}
(again the order of parsing/evaluation), so the compiler will barf if youuse strict;
as you always should. This one is easily fixable with declaringmy %hash
in prior statement, but #1 is not.
At the point where you are defining the hash, $hash{key1} does not exist, so you can't do this in one statement. You can do your own solution and use key key1 after you have defined it.
What's wrong with
my %hash = ( key1 => "Something", key2 => "Something" . "Else" );
?
Yes, I know those are placeholders, but whatever they may be you know them at the time you build the hash (or you wouldn't build it at all), so why don't you just join them together?
Firstly, I would just do this with the intermediate value. But, you have two separate more advanced options. I don't suggest /either/ of these if you're new to perl - in fact I rather like the intermediary value solution the best, but for completeness:
- You can use Tie::Hash which allows you to make an object accessible with hash syntax and hash style dereferencing (
->{key1}
), you can find more information on this method withperldoc perltie
, and the man page linked above forTie::Hash
; - You can abandon the idea of using a hash; and, use an object, or even Moose which will allow you to initialize the object from a hash, sharing the same value. I don't see much purpose in a real world example in doing this.
Here is a Moose example.
package Class;
use Moose;
has [qw/key1 key2/] => ( isa => 'Str', is => 'rw', init_arg => 'key1' );
my $o = Class->new( { key1 => 'foobar' } );
print $o->key1, $o->key2;
You can get fairly close, but I'm not sure it has value other than novelty:
$_->{key2} = $_->{key1} . "Else" for my $hash = { key1 => "Something" };
If creating the intermediate variable outside of %hash is off putting, then using a do block
may make it more aesthetically pleasing:
my %hash = (
do {
my $s = 'Something';
( key1 => $s, key2 => $s . 'Else' );
},
);
/I3az/
精彩评论