use strict;
my %h = ( apples => {
grannysmith => 5,
reddelicious => 3
},
oranges => 2,
pears => 3 );
print "$_\n" for keys %h;
# problem 1
print "$_\n" for keys %{%h->{apples}}; # Warning: Using a hash as a reference is deprecated.
# workaround
my $h_ref = \%h;
print "$_\n" for keys %{$h_ref->{apples}};
# problem 2
for my $fruit ( keys %{$h_ref->{apples}} ) {
if ( exists $fruit->{reddelicious} ) { # Error: Can't use string ("grannysmith") as a HASH ref while "strict refs" in use at test.pl line xx
print "Found red delicious key\n";
}
}for my $fruit ( keys %{$h{apples}} ) {
if ($fruit eq "reddelicious" ) { print "Found red delicious key\n";}
}
or#!/usr/bin/perl -w
use strict;
use warnings;
my $h;
$h->{apples}->{grannysmith} = 5;
$h->{apples}->{reddelicious} = 5;
$h->{oranges} = 2;
$h->{pears} = 5;
foreach my $fruitName (keys %{$h}) {
print "Fruit: $fruitName\n";
}
foreach my $appleName (keys %{$h->{apples}}) {
print "Apple name: $appleName\n";
}
foreach my $fruitName (keys %{$h}) {
if ($fruitName =~ /apples/) {
if (defined $h->{$fruitName}->{reddelicious}) {
print "found red delicious apple\n";
}
}
}
exit 0;print "$_\n" for keys %{%h->{apples}}; # Warning: Using a hash as a reference is deprecated.
Classic new person mistake :) See the "%h" I put in italics? You want "$h" instead. Reason: the signul -- @, %, $, or sometimes * -- in front determines what type of data you want out of the evaluation of the expression. You want the scalar value out, so you need to use $. Consider these examples:
%h = (a => 'apple', b => 'banana', c => 'corn');
%h; # evaluates to the list ('a', 'apple', 'b', 'banana', 'c', 'corn')
# although not specifically in that order
@h{'a', 'b'}; # evaluates to the list ('apple', 'banana')
$h{'a'}; # evaluates to the scalar 'apple'
Note how I used $h{'a'} and not $h->{'a'}. That's because h is a hash, not a reference to a hash. You made that mistake too.for my $fruit ( keys %{$h_ref->{apples}} ) { if ( exists $fruit->{reddelicious} ) { print "Found red delicious key\n"; } }
Think for a minute about what $fruit is. It's your hash key, which is a scalar string. It makes no sense to dereference a scalar string as a hash, which is exactly what the error told you. It's the same as writing "reddelicious"->{reddelicious}. I don't know what you're trying to do with this bit of code. If you want to see if there exists 'reddelicious" key in 'apples', then this suffices:
if (exists $h{'apples'}->{'reddelicious'}) { ... }
Note the indirection operator on the SECOND part. That's because your first part is a HASH, which contains a HASH REFERENCE. If you want to find what fruit has a key 'reddelicious', then you do this:
for my $fruit ( keys %h ) { if ( ref( $h{$fruit} ) eq 'HASH') && exists $h{$fruit}->{reddelicious} ) { print "Found red delicious key\n"; } }
You need to check with ref() the type of data in each key since your hash %h mixes scalars and hash references.my $foo = 1234;
my @foo = ('bar', 'baz');
my %foo = (one => 1, two => 2, three => 3, four => 4);
printf "%s\n", $foo;
printf "%s\n", $foo[ 0 ];
printf "%s\n", $foo{ 'three' };
What is the output? Better question is, how does perl tell the difference between $foo, @foo, and %foo in those print statements?!?# types of scalars
1234;
'this is a string';
# types of lists
(1, 2, 3, 4);
('foo', 'bar', 'baz');
(a => 'one', b => 'two', c => 'three');
('a', 'one', 'b', 'two', 'c', 'three');
No hashes! You might be tempted to say that list #3 is a hash, but it's not. It's just a fancy way of writing exactly the same list #4. That is, '=>' in perl is almost exactly like ',' (except it always interprets its left hand side as a string, even when not quoted).# scalar reference
\1234;
\'this is a string';
# list reference
[ 1, 2, 3, 4 ];
['foo', 'bar', 'baz'];
[a => 'one', b => 'two', c => 'three'];
['a', 'one', 'b', 'two', 'c', 'three'];
\@foo;
# hash reference
{a => 'one', b => 'two', c => 'three'};
{'a', 'one', 'b', 'two', 'c', 'three'};
\%foo;
# subroutine reference
sub { print "test\n"; }
\&foo;
But again, those are all scalars. They just happen to be references to data of another type. And when you have a scalar that is a reference, that's when the indirection operator comes in, or sometimes you have two signuls together:
$$scalarref; ${$scalarref};
@$listref; @{$listref};
%$hashref; %{$hashref};
&$subref;use Moose;)
--- doit_orig.pl 2009-03-27 19:09:03.000000000 +1100
+++ doit.pl 2009-03-27 19:25:04.000000000 +1100
@@ -1,3 +1,5 @@
+#!/usr/bin env perl
+use warnings;
use strict;
my %h = ( apples => {
@@ -10,15 +12,16 @@
print "$_\n" for keys %h;
# problem 1
-print "$_\n" for keys %{%h->{apples}}; # Warning: Using a hash as a reference is deprecated.
+print "$_\n" for keys %{ $h{apples} }; # fixed!
# workaround
my $h_ref = \%h;
print "$_\n" for keys %{$h_ref->{apples}};
# problem 2
+$DB::single=1;
for my $fruit ( keys %{$h_ref->{apples}} ) {
-if ( exists $fruit->{reddelicious} ) { # Error: Can't use string ("grannysmith") as a HASH ref while "strict refs" in use at test.pl line xx
+if ( $fruit eq 'reddelicioius' ) { # no warning now!
print "Found red delicious key\n";
}
}
Dumper the recalcitrant structure to stdout. Enlightenment follows (usually).use strict;
use warnings; # always use this
my %h = (
apples => {
grannysmith => 5,
reddelicious => 3
},
oranges => 2,
pears => 3 );
for my $fruit ( keys %h )
{
if ( ref $h{$key} eq "" )
{
print $h{$fruit}, " ", $fruit, "\n";
}
elsif ( ref $h{$key} eq "HASH" )
{
for my $type ( keys %{$h{$key}} )
{
print $type, " ", $fruit, " ", $h{$fruit}->{$type}, "\n";
}
}
else
{
print STDERR ref $h{$key}, " references not permitted\n";
exit( -1 );
}
}
print "$_\n" for keys %{ $h{apples} }posted by suedehead at 10:06 PM on March 26, 2009