Какой смысл `использовать vars` в этой подпрограмме Perl? - PullRequest
10 голосов
/ 14 февраля 2010

В одной из глав Мастеринг Perl Брайан Д Фой показывает этот фрагмент из Список :: 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;
}

Я не понимаю, в чем смысл линии use vars qw($a $b). Даже если я это прокомментирую, я получу тот же вывод и предупреждения.

Ответы [ 3 ]

11 голосов
/ 14 февраля 2010

Это сделано потому, что List :: Util использует функцию redu () внутри.

При отсутствии use vars при использовании функции выдается следующее предупреждение:

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.

Вы можете убедиться в этом сами, запустив следующий код:

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";

И затем запустить его снова с отключенной use vars.

2 голосов
/ 14 февраля 2010

Как отмечает DVK, если мы запустим код с закомментированным use vars, мы получим предупреждение об использовании переменных только один раз.

Другой способ подавления предупреждения - на стороне вызывающего абонента, то есть при вызове reduce, а не в функции reduce. Это необходимо делать при использовании функций из List::Util или List::MoreUtils, которые принимают ссылки на код (например, pairwise). Оба эти подхода работают на стороне вызывающего:

my @sums = pairwise { no warnings 'once'; $a + $b } @x, @y;

my @sums = pairwise { our($a, $b);        $a + $b } @x, @y;
0 голосов
/ 22 февраля 2010

Из параграфа сразу после того, как этот код объясняет это. В одной области видимости есть сочетание пакетных и лексических переменных:

Остальная часть Reduce работает как сортировка, помещая два элемента в переменные пакета $ a и $ b. Грэхем определяет лексические переменные с этими именами и немедленно присваивает глобам типов $ a и $ b в вызывающем пакете, используя символические ссылки. После этого значения $ a и $ b являются лексическими версиями. Когда он вызывает аргумент подпрограммы & {$ code} (), этот код просматривает переменные пакета, которые действовали, когда я писал подпрограмму. Понял? Внутри Reduce я использую лексические версии, но внутри $ code я использую версии пакетов из вызывающего пакета. Вот почему Грэм сделал их псевдонимами друг друга.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...