Two questions regarding the following code :
%h1 = {
'key1' => ( 1, 2, 3 ),
'key2' => ( 4, 5, 6 )
};
%h开发者_开发百科2 = {
'key1' => [ 1, 2, 3 ],
'key2' => [ 4, 5, 6 ]
};
print $(@h1{'key2'})[1];
Q1 : What is the difference between h1 and h2? Please don't say 'one is a hash of lists and another hash of arrays'... Rather, I want to know what that translates to in terms of usage.
Q2 : Why does the the reference $(@h1{'key2'})[1]
in the print statement not compile? This is my thinking : I want access the array/list corresponding to 'key2' : @h1{'key2'}
. Then I want to access the scalar at the index of 1 in that list/array : $(@h1{'key2'})[1]
. Why is this wrong ? This variable referencing stuff is confusing.
Neither of those work like you think. use strict and use warnings always.
%h1 = {
'key1' => ( 1, 2, 3 ),
'key2' => ( 4, 5, 6 )
};
You're trying to assign a hashref ( {} construct ) to a hash. It gets stringified into a scalar and is used as a key in %h1, with a value of undef. In addition, cause you're using lists ( () construct), it gets flattened and you're creating the hash:
%href = ( key1 => 1,
2 => 3,
key2 => 4,
5 => 6,
);
In the latter case, you correctly create your hash with array refs ( [] construct), but you're still assigning a href to the hash. You want to do:
%h1 = (
'key1' => [ 1, 2, 3 ],
'key2' => [ 4, 5, 6 ]
);
This creates %h1 in list context and your values in scalar context via reference.
The difference: they're both wrong! :)
Lists are flat structures; you can't have lists of lists, you just get a (one-dimensional) list back.
References are scalars. So %h1 = { ... }
doesn't make sense. What you're doing is just assigning a one-element list to %h1
, which gets stringified and turned into a key. This is equivalent to
%h1 = ( 'HASH(0x1fb872a0)' => undef );
where the key is the stringified version of whatever memory address held that hash reference.
To make a hash of arrays, do this:
my %h1 = ( key1 => [ 1, 2, 3 ], key2 => [ 4, 5, 6 ] );
If you want a reference to a hash of arrays, you can use:
my $ref = { key1 => [ 1, 2, 3 ], key2 => [ 4, 5, 6 ] };
or
my $ref = \%h1;
Finally, to access your structure elements, you can use:
print $h1{key2}[1];
or
print $ref->{key2}[1];
In the latter case we use the ->
operator to dereference the structure. For subsequent levels, ->
is assumed, but you can also write
print $ref->{key2}->[1];
if you find that clearer.
To get the complete structure back from the reference (e.g. to use keys
) you need to use another form of dereferencing:
my @keys = keys %$ref; # or more explicitly %{ $ref }
To get at the full inner structure, it's the same thing:
my @a2 = @{ $ref->{key2} };
All of this is covered in full detail in the following excellent Perl docs:
- Perl references tutorial
- Perl references
- Perl data structures cookbook
and others.
The difference is that the %h1
assignment is completely wrong and the %h2
assignment is almost right.
Perl uses parentheses to create a list, which may be assigned to an array or a hash:
@a = (1, 2, 3);
%a = (foo => 'bar', 7 => 3);
Perl uses brackets to create a list reference, which may be assigned to a scalar.
$a = [ 1, 2, 3 ];
Perl uses braces to create a hash reference, which may be assigned to a scalar.
$a = { key1 => 1, key2 => 2 };
The other important point to keep in mind is that values of hash tables are always scalars. There are no "hashes of lists" of "hashes of hashes" in Perl -- those are terms of convenience that really mean "hashes of list references" and "hashes of hash references".
With that in mind, let's look at your examples:
%h1 = { ... };
is already wrong. Braces create a hash reference, which are treated as a single scalar, and what you are doing is equivalent to this:
$scalar = { ... };
%h1 = ( "$scalar" => undef );
so %h1
contains a single key with an ugly name like HASH(0x54321098)
instead of what you mean. Instead, say
%h1 = ( ... )
Moving on,
%h1 = (
'key1' => ( 1, 2, 3 ),
'key2' => ( 4, 5, 6 )
);
also does not do what it looks like you want to do. There are lists, not list references, in this assignment, and another thing to keep in mind is that Perl "flattens" lists. If you think of =>
as just as fancy synonym for a comma (which is almost true), then you'll see this assignment is equivalent to either:
%h1 = ( 'key1', 1, 2, 3, 'key2', 4, 5, 6 );
or
%h1 = ( 'key1' => 1,
2 => 3,
'key2' => 4,
5 => 6 );
creating a hash table with four key value pairs, not the two you were expecting.
If we fix the braces around the %h2
assignment, then
%h2 = ( key1 => [ 1, 2, 3 ],
key2 => [ 4, 5, 6 ] );
will do what you expect. Remember that the values of hash tables have to be scalars, and that a list reference is a scalar. You may then say something like $h2{'key1'}[1]
to get at the individual list elements (in this case, 2).
If it compiles %h1
is the associative array
( 'HASH=(...)' => undef )
Since you are passing it an array reference instead of a list of key-value pairs.
If the expression for %h1
were valid, the literal hash would be:
{ key1 => 1, 2 => 3, key2 => 4, 5 => 6 }
Just the same way as if you created it like so:
my %h1 = ( key1 => 1, 2 => 3, key2 => 4, 5 => 6 );
It processes each list together, regardless of parenthesis.
As a result, you would be dereferencing '4'(or '1') as an array--of course you're currently trying to dereference an undef
.
But chances are constructing it like that, when you do @h1{'key2'}
, you get a list ( '4' )
which if evaluated in a scalar context becomes '1'
Even if $h1{'key2'}
pointed to an array @h1{'key2'}
gives you ( [ 4, 5, 6 ] )
and not ( 4, 5, 6 )
精彩评论