开发者

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.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜