How to create an anonymous array ([]) with 'empty slots'?
I can create an array with 'empty slots' in it:
$ perl -wde 1
...
DB<1> $x[2] = 0
DB<2> x \@x
0 ARRAY(0x103d5768)
0 empty slot
1 empty slot
2 0
or
DB<3> $#y = 4
DB<4> x \@y
0 ARRAY(0x103d5718)
0 empty slot
1 empty slot
2 empty slot
3 empty slot
4 empty slot
Please note: this is not the same as assigning undef
.
But how do I specify that for an anonymous array using [
and ]
?
This will not work:
DB<5> x [,,0]
syntax error at (eval 27)[/usr/local/lib/perl5/5.10.0/perl5db.pl:638] line 2, near "[,"
And this fails too, since I only get the assigned value:
DB<6> x []->[2] = 0
0 0
Bonus question: how 开发者_StackOverflow中文版can I check for an 'empty array slot' in my Perl script?
Background: In my test scripts I would like to be able to compare array contents precisely. For example I want to distinguish between 'not assigned' and 'assigned with an undef value'.
Thanks for any insights.
use feature qw/ say /;
use strict;
use warnings;
my $aref;
$#{$aref} = 4;
$aref->[2] = undef;
$aref->[3] = '';
foreach my $idx ( 0 .. $#{$aref} ) {
say "Testing $idx.";
say "\t$idx exists." if exists $aref->[$idx];
say "\t$idx defined." if defined $aref->[$idx];
}
OUTPUT:
Testing 0.
Testing 1.
Testing 2.
2 exists.
Testing 3.
3 exists.
3 defined.
Testing 4.
We pre-allocated five spots in the anonymous array, @{$aref}
. The top index is 4
. We are able to find what the top index is the same way we created it; by testing the value of $#{$aref}
. We can test for existence. We know everything between 0
and 4
was created. But Perl only reports "exists" for array elements that have specifically had something assigned to them (even if it's undef
). Therefore, $aref->[2]
is reported to exist, but isn't defined. Just for fun, we assigned ''
to $aref->[3]
to see a test report defined once. But the short story is that even though the array is pre-extended, we can still test for the difference between an element being initialized with undef
, and an element being undef
through array pre-extension, by using 'exists
'.
I can't say that's documented behavior of exists
. So there's no guarantee it wouldn't change someday. But it works on 5.8, 5.10, 5.12, and 5.14.
So, looking for a simple way to find which elements were initialized, which were defined, and which were not, here's an example:
use feature qw/ say /;
use strict;
use warnings;
my $aref;
$#{$aref} = 4;
$aref->[2] = undef;
$aref->[3] = '';
my @initialized = grep { exists $aref->[$_] } 0 .. $#{$aref};
my @defined = grep { defined $aref->[$_] } 0 .. $#{$aref};
my @uninitialized = grep { not exists $aref->[$_] } 0 .. $#{$aref};
my @init_undef = grep { exists $aref->[$_] and not defined $aref->[$_] } 0 .. $#{$aref};
say "Top index is $#{$aref}.";
say "These elements are initialized: @initialized.";
say "These elements are not initialized: @uninitialized.";
say "These elements were initialized with 'undef': @init_undef.";
say "These elements are defined: @defined."
That should do:
$a=[];
$#$a=4;
Update (replying to @hexcoder): In one statement:
$#{$a=[]}=4
And in one statement that returns the array:
$a = (map(($_,$#$_=4),[]))[0]
Though, not that I recommend using that construction...
Background: In my test scripts I would like to be able to compare array contents precisely. For example I want to distinguish between 'not assigned' and 'assigned with an undef value'.
You can check if the index is past the end. Beyond that, there's not much you can do.
$x = [];
undef $x->[9999];
print scalar @$x;
prints 10000. The undef $x->[9999]
is equivalent to $x->[9999] = undef;
Because none of the elements 0 to 9998 exist, perl will magically assign all of the intervening elements to undef
.
You can only do that kind of thing from XS code (see for example Devel::Peek
). Some, but not all, of it is exposed by the *::Util
packages. (I've been working on a debugging/tracing package, so I know more about this than anyone should need to....)
精彩评论