Demystifying the Perl glob (*)
In this question the poster asked how to do the following in one line:
sub my_sub {
my $ref_array = shift;
my @array = @$ref_array;
}
which with my knowledge of the basic Perl magic I would 开发者_运维知识库avoid by simply using something like:
sub my_sub {
my $ref_array = shift;
for (@$ref_array) {
#do somthing with $_ here
};
#use $ref_array->[$element] here
}
However in this answer one of SO's local monks tchrist suggested:
sub my_sub {
local *array = shift();
#use @array here
}
When I asked
In trying to learn the mid-level Perl magic, can I ask, what is it that you are setting to what here? Are you setting a reference to @array to the arrayref that has been passed in? How do you know that you create @array and not %array or $array? Where can I learn more about this * operator (perlop?). Thanks!
I was suggested to ask it as a new post, though he did give nice references. Anyway, here goes? Can someone please explain what gets assigned to what and how come @array gets created rather than perhaps %array or $array? Thanks.
Assignment to a glob
*glob = VALUE
contains some magic that depends on the type of VALUE
(i.e., return value of, say, Scalar::Util::reftype(VALUE)
). If VALUE
is a reference to a scalar, array, hash, or subroutine, then only that entry in the symbol table will be overwritten.
This idiom
local *array = shift();
#use @array here
works as documented when the first argument to the subroutine is an array reference. If the first argument was instead, say, a scalar reference, then only $array
and not @array
would be affected by the assignment.
A little demo script to see what is going on:
no strict;
sub F {
local *array = shift;
print "\@array = @array\n";
print "\$array = $array\n";
print "\%array = ",%array,"\n";
print "------------------\n";
}
$array = "original scalar";
%array = ("original" => "hash");
@array = ("orignal","array");
$foo = "foo";
@foo = ("foo","bar");
%foo = ("FOO" => "foo");
F ["new","array"]; # array reference
F \"new scalar"; # scalar reference
F {"new" => "hash"}; # hash reference
F *foo; # typeglob
F 'foo'; # not a reference, but name of assigned variable
F 'something else'; # not a reference
F (); # undef
Output:
@array = new array $array = original scalar %array = originalhash ------------------ @array = orignal array $array = new scalar %array = originalhash ------------------ @array = orignal array $array = original scalar %array = newhash ------------------ @array = foo bar $array = foo %array = FOOfoo ------------------ @array = foo bar $array = foo %array = FOOfoo ------------------ @array = $array = %array = ------------------ @array = orignal array $array = original scalar %array = originalhash ------------------
Additional doc at perlmod
and perldata
. Back in the days before references were a part of Perl, this idiom was helpful for passing arrays and hashes into subroutines.
With my admittedly less-than-wizard knowledge of Perl, I'll venture an answer. The * operator assigns the symbol table entry. As I understand it, @array, %array, and $array all refer to the same symbol table entry for the string 'array', but to different fields in that entry: the ARRAY, HASH, and SCALAR fields. So assigning local *array = shift;
actually assigns the entire local symbol table entry for 'array' (including the ARRAY, HASH, and SCALAR fields) to what was passed used in the caller.
精彩评论