Чем $ _ отличается от именованного ввода или аргументов цикла? - PullRequest
3 голосов
/ 23 марта 2011

Поскольку я много использую $ _, я хочу лучше понять его использование. $ _ - это глобальная переменная для неявных значений, насколько я понял и использовал ее.

Поскольку $ _, похоже, в любом случае задан, есть ли причины использовать именованные переменные цикла над $ _ помимо readability?

В каких случаях значение $ _ является глобальной переменной?

Так что, если я использую

for (@array){
    print $_;
}

или даже

print $_ for @array;

имеет тот же эффект, что и

for my $var (@array){
    print $var;
}

Но работает ли он так же? Я думаю, что это не совсем так, но каковы реальные различия?

Обновление

Кажется, что $ _ в этом примере даже правильно определено. Это уже не глобально? Я использую 5.12.3.

#!/usr/bin/perl
use strict;
use warnings;

my @array = qw/one two three four/;
my @other_array = qw/1 2 3 4/;

for (@array){
    for (@other_array){
        print $_;
    }
    print $_;
}

, который печатает правильно 1234one1234two1234three1234four.

Для глобального $ _ я бы ожидал 1234 4 1234 4 1234 4 1234 4 .. или я что-то упустил очевидно?

Когда $ _ глобален тогда?

Обновление

Хорошо, после прочтения различных ответов и более тщательно, я пришел к выводу:

Помимо читабельности, лучше избегать использования $ _, потому что неявная локализация $ _ должна быть известна и учитывать, иначе можно столкнуться с неожиданным поведением.

Спасибо за разъяснения по этому вопросу.

Ответы [ 5 ]

8 голосов
/ 23 марта 2011
are there reasons to use named loop variables over $_ besides readability?

Проблема не в том, названы они или нет. Проблема в том, являются ли они «переменными пакета» или «лексическими переменными».

См. Очень хорошее описание двух систем переменных, используемых в Perl "Как справиться со Scoping":

http://perl.plover.com/FAQs/Namespaces.html

переменные пакета являются глобальными переменными, и поэтому их следует избегать по всем обычным причинам (например, действие на расстоянии).

Избежание переменных пакета - это вопрос «правильной работы» или «сложнее вводить ошибки», а не вопрос «читабельности».

In what cases does it matter $_ is a global variable?

Везде.

Лучший вопрос:

In what cases is $_ local()ized for me?

Есть несколько мест, где Perl локализует () ize $ _ для вас, в первую очередь foreach, grep и map. Во всех других местах требуется, чтобы вы локально () использовали его самостоятельно, поэтому вы будете вносить потенциальную ошибку, когда неизбежно забудете это сделать. : -)

8 голосов
/ 23 марта 2011

Классический режим отказа при использовании $_ (неявно или явно) в качестве переменной цикла:

for $_ (@myarray) {
  /(\d+)/ or die;
  foo($1);
}

sub foo {
  open(F, "foo_$_[0]") or die;
  while (<F>) {
    ...
  }
}

где, поскольку переменная цикла в for / foreach привязана к фактическомуЭлемент списка означает, что while (<F>) перезаписывает @myarray строками, считанными из файлов.

3 голосов
/ 23 марта 2011

$ _ - это то же самое, что и наименование переменной, как во втором примере, с тем, как она обычно используется. $ _ - это просто сокращенное имя переменной по умолчанию для текущего элемента в текущем цикле, чтобы сэкономить при наборе текста при выполнении быстрого и простого цикла. Я склонен использовать именованные переменные, а не по умолчанию. Это делает более понятным, что это такое, и если мне понадобится выполнить вложенный цикл, то никаких конфликтов не будет.

Поскольку $ _ является глобальной переменной, вы можете получить неожиданные значения, если попытаетесь использовать ее значение, которое было в предыдущем блоке кода. Новый кодовый блок может быть частью цикла или другой операции, которая вставляет свои собственные значения в $ _, перезаписывая то, что вы ожидали там.

2 голосов
/ 23 марта 2011

Риск при использовании $ _ заключается в том, что он является глобальным (если вы не локализуете его с помощью local $_), и поэтому, если какая-то функция, которую вы вызываете в цикле, также использует $ _, эти два использования могут помешать.

По причинам, которые мне не ясны, это укусило меня лишь изредка, но я обычно локализую $ _, если использую его внутри пакетов.

1 голос
/ 23 марта 2011

В $_ нет ничего особенного, кроме того, что это параметр по умолчанию для многих функций.Если вы явно ограничиваете свой $_ значением my, perl будет использовать локальную версию $_, а не глобальную.В этом нет ничего странного, это как любая другая именованная переменная.

sub p { print "[$_]"; } # Prints the global $_
# Compare and contrast
for my $_ (b1..b5) { for my $_ (a1..a5) { p } } print "\n"; # ex1
for my $_ (b1..b5) { for       (a1..a5) { p } } print "\n"; # ex2
for       (b1..b5) { for my $_ (a1..a5) { p } } print "\n"; # ex3
for       (b1..b5) { for       (a1..a5) { p } } print "\n"; # ex4

Вывод будет слегка озадачен, пока вы не обнаружите, что perl сохранит исходное значение переменной цикла в циклевыход (см. perlsyn ).

Примечание ex2 выше.Здесь второй цикл использует лексическую область действия $_, объявленную в первом цикле.Тонкий, но ожидаемый.Опять же, это значение сохраняется при выходе, поэтому два цикла не мешают.

...