Какой смысл использовать vars в этой подпрограмме Perl?
В одной из глав Освоение Perl, brian d foy показывает этот фрагмент из 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;
}
Я не понимаю, что это за точка строки use vars qw($a $b)
. Даже если я прокомментирую это, я получаю тот же вывод и предупреждения.
Ответы
Ответ 1
Это делается потому, что List:: Util использует функцию reduce() внутри.
В период отсутствия 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
Как отмечает 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;
Ответ 3
Из параграфа сразу после этого кода это объясняется. Там сочетание пакетных и лексических переменных в той же области:
Остальная часть сокращения работает подобно сортировке, помещая два элемента в переменные пакета $a и $b. Грэм определяет лексические переменные с этими именами и сразу же присваивает typeglobs для $a и $b в вызывающем пакете, используя символические ссылки. После этого значения $a и $b являются лексическими версиями. Когда он вызывает аргумент подпрограммы & {$ code}(), этот код просматривает свои переменные пакета, которые действуют, когда я написал подпрограмму. Понял? Внутри уменьшить, я использую лексические версии, но внутри $code я использую версии пакета из вызывающего пакета. Вот почему Грэм сделал их псевдонимами друг друга.