Ответ Штеффена Ульриха вводит в заблуждение, поэтому мне придется ответить здесь. Возможно, я кое-что пропустил, но уже поздно. И Изучение Perl уже все это объясняет. ;)
Оператор local не работает в лексической области. Несмотря на то, что он говорит, это не ограничивается блоком, в котором находится. У людей обычно возникают проблемы с пониманием, потому что они не пробуют это делать. Такие термины, как «снаружи» и «внутри» вводят в заблуждение и опасны для местных.
Рассмотрим это использование, где есть функция, которая печатает глобальное значение $_
:
$_ = 'Outside';
show_it();
inside();
$_ = 'Outside';
show_it();
sub show_it { print "\$_ is $_\n"; }
sub inside {
local $_;
$_ = 'Inside';
show_it();
}
Когда вы запустите это, вы увидите, что значение $_
, установленное внутри блока, доступно за пределами блока:
$_ is Outside
$_ is Inside
$_ is Outside
local работает с переменными пакета. Он временно использует новое значение до конца блока. Однако как переменная пакета она изменяется повсюду в программе до тех пор, пока область local не изменится. заканчивается. У оператора есть лексическая область видимости, но он действует повсюду. Вы даете глобальной переменной временное значение, и эта глобальная переменная по-прежнему остается глобальной. Переменные local имеют глобальный эффект, но лексическое время жизни. Они изменяют значение везде в программе, пока эта область не закончится.
Как я уже писал ранее, неправильно говорить о «внутреннем» и «внешнем» с помощью local. Это «до» и «после». Я покажу еще немного из того, что будет в ближайшее время, где даже время распадается.
my совершенно другой. Он вообще не работает с пакетными переменными. Также называемые «лексическими переменными», они вообще не существуют вне своей области видимости (даже несмотря на то, что обратные магические модули, такие как PadWalker посмотри на них). Никакая другая часть программы не может их увидеть. Они видны только в своей области и под-областях, созданных в этой области.
Perl v5.10 позволяет нам создавать лексическую версию $_
(а также фиксированной и сделано экспериментально в v5.16 - не используйте его. См. также Хорошие, плохие и уродливые лексические $ _ в Perl 5.10+). В моем предыдущем примере я могу использовать это:
use v5.10;
$_ = 'Outside';
show_it();
inside();
$_ = 'Outside';
show_it();
sub show_it { print "\$_ is $_\n"; }
sub inside {
my $_;
$_ = 'Inside';
show_it();
}
Теперь вывод другой. Лексическая $_
действует так же, как и любая другая лексическая переменная. Это не влияет ни на что, выходящее за пределы его области видимости, опять же, потому что эти переменные существуют только в своей лексической области видимости:
$_ is Outside
$_ is Outside
$_ is Outside
Но, чтобы ответить на исходный вопрос. Сообщение Perlmonks Встроенные функции со значением по умолчанию $ _ все еще хороши, но я не думаю это актуально здесь. Эти функции используют $_
, а не устанавливают его.
Главное, что нужно знать о Perl, - это то, что на него нет короткого ответа. Perl делает то, что имеет смысл, а не то, что делает его последовательным. В конце концов, это язык постмодерна.
Способ не беспокоиться об изменении $_
- это не изменять $_
. Избегайте его использования. У нас есть много подобных советов по эффективному программированию на Perl.
для каждого
Конструкции цикла foreach и его for
синоним используют локализованную версию $_
для ссылки на текущую тему. . Внутри цикла, включая все, что вызывает цикл, используется текущая тема:
use v5.10;
$_ = 'Outside';
show_it();
sub show_it { say "\$_ is $_"; }
my @array = 'a' .. 'c';
foreach ( @array ) {
show_it();
$_++
}
say "array: @array";
Обратите внимание на массив после цикла foreach
. Несмотря на то, что foreach
локализует $_
, Perl присваивает этому значению псевдоним, а не копирует его. Изменение управляющей переменной изменяет исходное значение, даже если это значение находится во внешней лексической области:
$_ is Outside
$_ is a
$_ is b
$_ is c
array: b c d
Не используйте $_
в качестве управляющей переменной. Я использую значение по умолчанию только в очень коротких программах, в основном потому, что я хочу, чтобы управляющая переменная имела значимое имя в больших программах.
карта и grep
Подобно foreach
, map
и grep
используйте $_
для управляющей переменной. Для них нельзя использовать другую переменную. Вы по-прежнему можете влиять на переменные за пределами области действия с помощью псевдонима, повышающего производительность, который я показал в предыдущем разделе.
Опять же, это означает, что есть некоторая утечка прицела. Если вы измените $_
внутри блока и $_
был одним из элементов во входном списке, внешний $_
изменится:
use v5.10;
$_ = 'Outside';
my @transformed = map { $_ = 'From map' } ( $_ );
say $_;
Для умеренно сложных встроенных блоков я присваиваю $_
лексической переменной:
my @output = map { my $s = $_; ... } @input;
И если вы действительно нервничаете по поводу $_
, не проделывайте злую шутку с map
внутри map
:
my @words = map {
map { split } $_
} <>;
Это глупый пример, но я делал такие вещи в прошлом, когда мне нужно было превратить тему в список.
пока (‹>)
В Perl есть удобная небольшая идиома, которая присваивает следующей строке дескриптора файла $_
. Это означает, что вместо этого:
while( defined( $_ = <> ) )
Вы можете получить то же самое с:
while( <> )
Но какое бы значение ни попало в $_
, остается в $_
.
$_ = "Outside\n";
show_it();
sub show_it { print "\$_ is $_" }
while( <DATA> ) {
show_it();
}
show_it();
__DATA__
first line
second line
third line
Результат выглядит немного странно, потому что последняя строка не имеет значения, но это последнее значение, присвоенное $_
: undef, которое оператор ввода строки назначил до того, как тест defined
остановил цикл:
$_ is Outside
$_ is first line
$_ is second line
$_ is third line
$_ is
Поместите last
туда, и результат изменится
$_ = "Outside\n";
show_it();
sub show_it { print "\$_ is $_" }
while( <DATA> ) {
show_it();
last;
}
show_it();
__DATA__
first line
second line
third line
Теперь последним присвоенным значением была первая строка:
$_ is Outside
$_ is first line
$_ is first line
Если вам это не нравится, не используйте идиому:
while( defined( my $line = <> ) )
Сопоставление с образцом
Оператор подстановки s///
по умолчанию привязывается к $_
и может его изменить (в этом вся суть). Но с v5.14 вы можете использовать флаг /r
, который оставляет исходный и возвращает измененную версию.
Оператор сопоставления m//
также может изменять $_
. Он не меняет значение, но может установить флаг позиции. Вот как Perl может выполнять глобальные сопоставления в скалярном контексте:
use v5.10;
$_ = 'Outside';
show_it();
sub show_it { say "\$_ is $_ with pos ", pos(); }
foreach my $time ( 1 .. 5 ) {
my $scalar = m/./g;
show_it();
}
show_it();
Некоторые из скалярных настроек в $_
изменяются, даже если значение остается тем же:
$_ is Outside with pos
$_ is Outside with pos 1
$_ is Outside with pos 2
$_ is Outside with pos 3
$_ is Outside with pos 4
$_ is Outside with pos 5
$_ is Outside with pos 5
У вас, вероятно, не возникнет проблем с этим. Вы можете сбросить позицию при неудачном совпадении с $_
. То есть, если вы не используете флаг /c
. Несмотря на то, что скалярное значение не изменилось, часть его бухгалтерского учета изменилась. Это была одна из проблем с лексическим $_
.
С сопоставлением происходит еще одна любопытная вещь. Переменные для каждого матча имеют динамическую область видимости. Они не меняют значения, которые у них были во внешней области:
use v5.10;
my $string = 'The quick brown fox';
OUTER: {
$string =~ /\A(\w+)/;
say "\$1 is $1";
INNER: {
$string =~ /(\w{5})/;
say "\$1 is $1";
}
say "\$1 is $1";
}
Значение $1
в области OUTER
не заменяется $1
в INNER
:
$1 is The
$1 is quick
$1 is The
Если у вас болит голова, не используйте переменные для каждого совпадения. Назначьте их сразу (и только после успешного совпадения):
my $string = 'The quick brown fox';
OUTER: {
my( @captures ) = $string =~ /\A(\w)/;
INNER: {
my $second_word;
if( $string =~ /(\w{5})/ ) {
$second_word = $1
}
}
}
person
brian d foy
schedule
04.12.2015
$_
во всем вашем коде. - person Sinan Ünür   schedule 04.12.2015$_
в правильной ситуации может сделать заявление более четким и менее избыточным. Например, одно из моих любимых применений - запуск функции для каждого элемента массиваfunction($_) for @values;
. Однако использование$_
в двойном цикле немедленно напоминает опытным программистам Perl об отладочных кошмарах. - person Christopher Bottoms   schedule 05.12.2015@array_of_array_refs
(что-то вродеARRAY(0x183ea68)
). - person Christopher Bottoms   schedule 05.12.2015