What's the point of `use vars` in this Perl subroutine?
In one of the chapters in Mastering Perl, brian d foy shows this snippet from List::Util:
sub reduce(&@) {
my $code = shift;
no strict "refs";
return shift unless @_ > 1;
use vars qw($a $b);
my $caller = caller;
local(*{$caller . "::a"}) = \my $a;
local(*{$caller . "::b"}) = \my $b;
$a = shift;
foreach(@_) {
$b = $_;
$a = &{$code}();
}
$a;
}
I don't understand what's the point of the use vars qw($a $b)
line. Even if I comment it, I get the same output &开发者_C百科amp; warnings.
This is done because List::Util uses reduce() function internally.
In the abscence of use vars
, the following warning is given when the function is used:
Name "List::MyUtil::a" used only once: possible typo at a.pl line 35.
Name "List::MyUtil::b" used only once: possible typo at a.pl line 35.
You can see this for yourself by running the following code:
use strict;
use warnings;
package List::MyUtil;
sub reduce (&@) {
# INSERT THE TEXT FROM SUBROUTINE HERE - deleted to save space in the answer
}
sub x {
return reduce(sub {$a+$b}, 1,2,3);
}
package main;
my $res = List::MyUtil::x();
print "$res\n";
And then running it again with use vars
disabled.
As DVK notes, if we run the code with the use vars
commented out, we will get a warning about variables being used only once.
Another way to suppress the warning is on the caller side -- that is, in the call to reduce
rather than within the reduce
function. One has to do this when using functions from List::Util
or List::MoreUtils
that take code references (for example, pairwise
). Both of these approaches work on the caller side:
my @sums = pairwise { no warnings 'once'; $a + $b } @x, @y;
my @sums = pairwise { our($a, $b); $a + $b } @x, @y;
From the paragraph right after that code explains it. There's a mix of package and lexical variables in the same scope:
The rest of reduce works like sort by putting two elements into the package variables $a and $b. Graham defines the lexical variables with those names, and immediately assigns to the typeglobs for $a and $b in the calling package by using symbolic references. After that the values of $a and $b are the lexical versions. When he calls the subroutine argument &{$code}(), that code looks at its package variables, which are the ones in effect when I wrote the subroutine. Got that? Inside reduce, I'm using the lexical versions, but inside $code, I'm using the package versions from the calling package. That's why Graham made them aliases of each other.
精彩评论