开发者

How to check if a Perl hash is defined when it doesn't have any key/value pairs

I'm trying to figure out a way to check if a hash has been declared in a Perl script while inside a module function.

Given the following script (file script.pl):

#!/usr/bin/perl -w

use strict;
use checkHash;

our %testHash = ("key"=>"value");

print &checkHash() ? 1 : 0;

Along with this module (checkHash.pm);

sub checkHash {
    if(%main::testHash) {
        return 1;
    }
    else {
        return 0;
    }
}

1;

Running on a Mac with OS X v10.6.7 (Snow Leopard) and Perl v5.10.0, the return value of checkHash is "1" which I would expect. However, if I remove the key value pair from the script by changing the line:

our %testHash = ("key"=>"value");

to:

our %testHash = ();

The return value is "0". My original assumption开发者_JS百科 was that this would be "1", but after reading about the way the test I'm using is testing for the size in the hash, I see why that was incorrect thinking.

Is there a test that can be used in the checkHash module that will return true if the hash it's testing exists, but doesn't have any keys assigned to it?


defined() is not a meaningful test on aggregates (arrays and hashes). perldoc -f defined has this to say:

Use of "defined" on aggregates (hashes and arrays) is deprecated. It used to report whether memory for that aggregate has ever been allocated. This behavior may disappear in future versions of Perl. You should instead use a simple test for size:

               if (@an_array) { print "has array elements\n" }
               if (%a_hash)   { print "has hash members\n"   }


Testing whether a given symbol has been declared is almost certainly useless and a desire to perform it is indicative of a design problem. For the sake of completeness, however, here's tests for both lexical and dynamic symbols:

Find out if the lexical symbol $whoopee has been declared:

use Try::Tiny;
my $declared = try { use strict; $whoopee; 1 };

Find out if any dynamic symbol called FooPackage::whoopee has been declared (including hashes that spell their names %FooPackage::whoopee):

my $declared = exists $FooPackage::{whoopee};


See perldoc perldata

If you evaluate a hash in scalar context, it returns false if the hash is empty. If there are any key/value pairs, it returns true; more precisely, the value returned is a string consisting of the number of used buckets and the number of allocated buckets, separated by a slash.

That explains why your defined test seemed to work.


You can just count the keys:

sub checkHash {
    return ( scalar keys %main::testHash ) ? 1 : 0;
}

perl -le 'my %h; print ( scalar keys %h ) ? 1 : 0;'
0
perl -le 'my %h = (foo=>1); print ( scalar keys %h ) ? 1 : 0;'
1
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜