Array of hashes and strict refs - help!

N

Noel Sant

When I run my (test) program below, I get the following error:

Can't use string ("file") as a HASH ref while "strict refs" in use at
D:\Houseke
eping\BackupWithZip\Scripts\hashtest.pl line 28, <INPUT_FILE> line 2.

The camel book says this means only hard references are allowed by "use
strict refs", not symbolic ones. But this is more or less what the camel
book (2nd edition) says to do with arrays of hashes (pp268/9). Why is "file"
a symbolic ref? Where am I going wrong?

TIA

Noel

# Work out how to use an array of hashes with strict refs
#
use strict;

my $input_line; my $folder; my $file;
my @array; my %hash;
my $key; my $i;

# Lines in test.txt have two strings: a folder name and a file name,
# separated by spaces
open INPUT_FILE, "test.txt"
or die "Can't open test.txt\n";
while (!eof INPUT_FILE) {
$folder = "";
$file = "";
chomp($input_line = <INPUT_FILE>);
# Lots of checking of input line for double quotes and spaces,
# but with a simple line ("aaa bbb") ...
($folder, $file) = split (/\s+/, $input_line);
%hash = (
folder => $folder,
file => $file,
);
push @array, %hash;
}
%hash = ();
foreach $i (@array) {
for $key (keys %{$array[$i]}) { # <=== line 28
print "$key name is $array[$i]{$key}\n";
}
}
close INPUT_FILE;
 
P

Paul Lalli

When I run my (test) program below, I get the following error:

Can't use string ("file") as a HASH ref while "strict refs" in use at
D:\Houseke
eping\BackupWithZip\Scripts\hashtest.pl line 28, <INPUT_FILE> line 2.

The camel book says this means only hard references are allowed by "use
strict refs", not symbolic ones. But this is more or less what the camel
book (2nd edition) says to do with arrays of hashes (pp268/9). Why is "file"
a symbolic ref? Where am I going wrong?

TIA

Noel

# Work out how to use an array of hashes with strict refs
#
use strict;

my $input_line; my $folder; my $file;
my @array; my %hash;
my $key; my $i;

# Lines in test.txt have two strings: a folder name and a file name,
# separated by spaces
open INPUT_FILE, "test.txt"
or die "Can't open test.txt\n";
while (!eof INPUT_FILE) {
$folder = "";
$file = "";
chomp($input_line = <INPUT_FILE>);
# Lots of checking of input line for double quotes and spaces,
# but with a simple line ("aaa bbb") ...
($folder, $file) = split (/\s+/, $input_line);
%hash = (
folder => $folder,
file => $file,
);
push @array, %hash;
^^^^^
You can't push a hash into an array. You want to push a reference to that
hash into the array:
push @array, \%hash;

}
%hash = ();
foreach $i (@array) {
for $key (keys %{$array[$i]}) { # <=== line 28
print "$key name is $array[$i]{$key}\n";
}
}
close INPUT_FILE;

What was happening is that the original hash was getting flattened, adding
four new elements to the array. One of those elements was the string
"file", which you then tried to use as a hashref in the foreach loop.

Paul Lalli
 
P

Paul Lalli

^^^^^
You can't push a hash into an array. You want to push a reference to that
hash into the array:
push @array, \%hash;

Actually, looking again, you're changing the contents of %hash each time
through the loop. That's going to cause problems if you keep adding
references to the same variable. Two solutions - change the scope of my
%hash to be within the while loop only, or instead push an anonymous hash
containing the current contents of %hash:
push @array, { %hash };

Paul Lalli
 
J

James Willmore

When I run my (test) program below, I get the following error:

Can't use string ("file") as a HASH ref while "strict refs" in use at
D:\Houseke
eping\BackupWithZip\Scripts\hashtest.pl line 28, <INPUT_FILE> line 2.

The camel book says this means only hard references are allowed by "use
strict refs", not symbolic ones. But this is more or less what the camel
book (2nd edition) says to do with arrays of hashes (pp268/9). Why is
"file" a symbolic ref? Where am I going wrong?

TIA

Noel

# Work out how to use an array of hashes with strict refs #
use strict;

my $input_line; my $folder; my $file; my @array; my %hash;
my $key; my $i;

You have declared global variables ... read on :)

# Lines in test.txt have two strings: a folder name and a file name, #
separated by spaces
open INPUT_FILE, "test.txt"
or die "Can't open test.txt\n";
while (!eof INPUT_FILE) {

Go back and re-read the Camel book. You don't need this. A simple

while(<INPUT_FILE>) {

works ;-)
$folder = "";
$file = "";

There really isn't a need to do this either. In fact, to make sure the
variables are empty to begin with, you could do something like ...

my $folder = "";

However, when you first declare a variable, it's going to be 'undef'
anyway, so why bother. Better yet, why not declare the variables within
the block instead of outside the block. Right now, they're global. There
really isn't a point in declaring them globally - since they only "live"
within the block.

chomp($input_line = <INPUT_FILE>);
# Lots of checking of input line for double quotes and spaces, # but
with a simple line ("aaa bbb") ...
($folder, $file) = split (/\s+/, $input_line); %hash = (
folder => $folder,
file => $file,
);
push @array, %hash;

The hash is being flattened. If you want an array of hashes, then use a
reference to the hash ...

push @array, \%hash;
}
%hash = ();

Now ... why did you do this? During each loop through the the hash, the
hash values are being replaced. And, again, the life of this variable in
within the block, so why declare it globally? Declare it at the top of
the block and each time through the loop, it will get reinitialized.
foreach $i (@array) {
for $key (keys %{$array[$i]}) { # <=== line 28
print "$key name is $array[$i]{$key}\n";
}
}
close INPUT_FILE;

Just a few general comments. Go back and re-read the Camel book. And
also read perlstyle (unless you're newsreader butchered your code :) ).
Review some of the posts here and see examples of what I was talking
about.

HTH

--
Jim

Copyright notice: all code written by the author in this post is
released under the GPL. http://www.gnu.org/licenses/gpl.txt
for more information.

a fortune quote ...
"To YOU I'm an atheist; to God, I'm the Loyal Opposition." --
Woody Allen
 
B

Ben Morrow

The hash is being flattened. If you want an array of hashes, then use a
reference to the hash ...

push @array, \%hash;

Or, perhaps more clearly:

($folder, $file) = split ...;
push @array, {
folder => $folder,
file => $file,
};

No need for a temporary %hash at all.

Ben
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top