3.8 References to Hashes
Just as
you can take a reference to an array, you can also take a reference
to a hash. Once again, you use the backslash as the
"take a reference to" operator:
my %gilligan_info = (
name => 'Gilligan',
hat => 'White',
shirt => 'Red',
position => 'First Mate',
);
my $hash_ref = \%gilligan_info;
You can dereference a hash reference to
get back to the original data. The strategy is similar to
dereferencing an array reference. Write the hash syntax as you would
have without references, and then replace the name of the hash with a
pair of curly braces surrounding the thing holding the reference. For
example, to pick a particular value for a given key, use:
my $name = $ gilligan_info { 'name' };
my $name = $ { $hash_ref } { 'name' };
In this case, the curly braces have two different meanings. The first
pair denotes the expression returning a reference, while the second
pair delimits the expression for the hash key.
To perform an operation on the entire hash, you proceed similarly:
my @keys = keys % gilligan_info;
my @keys = keys % { $hash_ref };
As with array references, you can use shortcuts to replace the
complex curly-braced forms under some circumstances. For example, if
the only thing inside the curly braces is a simple scalar variable
(as shown in these examples so far), you can drop the curly braces:
my $name = $$hash_ref{'name'};
my @keys = keys %$hash_ref;
Like an array reference, when referring to
a specific hash element, you can use an arrow form:
my $name = $hash_ref->{'name'};
Because a hash reference fits wherever a scalar fits, you can create
an array of hash references:
my %gilligan_info = (
name => 'Gilligan',
hat => 'White',
shirt => 'Red',
position => 'First Mate',
);
my %skipper_info = (
name => 'Skipper',
hat => 'Black',
shirt => 'Blue',
position => 'Captain',
);
my @crew = (\%gilligan_info, \%skipper_info);
Thus, $crew[0] is a hash reference to the
information about Gilligan. You can get to
Gilligan's name via any one of:
${ $crew[0] } { 'name' }
my $ref = $crew[0]; $$ref{'name'}
$crew[0]->{'name'}
$crew[0]{'name'}
On that last one, you can still drop the
arrow between "subscripty kinds of
things," even though one is an array bracket and one
is a hash brace.
Let's print a crew roster:
my %gilligan_info = (
name => 'Gilligan',
hat => 'White',
shirt => 'Red',
position => 'First Mate',
);
my %skipper_info = (
name => 'Skipper',
hat => 'Black',
shirt => 'Blue',
position => 'Captain',
);
my @crew = (\%gilligan_info, \%skipper_info);
my $format = "%-15s %-7s %-7s %-15s\n";
printf $format, qw(Name Shirt Hat Position);
for my $crewmember (@crew) {
printf $format,
$crewmember->{'name'},
$crewmember->{'shirt'},
$crewmember->{'hat'},
$crewmember->{'position'};
}
That last part looks very repetitive. You can shorten it with a hash
slice. Again, if the original syntax is:
@ gilligan_info { qw(name position) }
the hash slice notation from a reference looks like:
@ { $hash_ref } { qw(name position) }
You can drop the first brace pair because the only thing within is a
simple scalar value, yielding:
@ $hash_ref { qw(name position) }
Thus, you can replace that final loop with:
for my $crewmember (@crew) {
printf $format, @$crewmember{qw(name shirt hat position)};
}
There is no shortcut form with an arrow (->)
for array slices or hash slices, just as there is no shortcut for
entire arrays or hashes.
A hash reference prints as a string
that looks like HASH(0x1a2b3c), showing the
hexadecimal memory address of the hash. That's not
very useful to an end user and only barely more usable to the
programmer, except as an indication of the lack of appropriate
dereferencing.
|