Какова область по умолчанию цикла foreach в Perl? - PullRequest
16 голосов
/ 10 февраля 2010

В Perl использование my в цикле foreach имеет какой-либо эффект? Кажется, что индексная переменная всегда является локальной независимо от того, используется «my» или нет. Таким образом, вы можете опустить my в цикле foreach и по-прежнему иметь частную область видимости в теле цикла?

Как видно, при использовании цикла for существует разница между использованием / неиспользованием my:

use strict; 
use warnings; 

my ($x, $y) = ('INIT', 'INIT'); 

my $temp = 0; 

for ($x = 1; $x < 10; $x++) {
 $temp = $x+1; 
}

print "This is x: $x\n";   # prints 'This is x: 10'. 

for (my $y = 1; $y < 10; $y++) {
 $temp = $y+1; 
}

print "This is y: $y\n";   # prints 'This is y: INIT'. 

Но на foreach это, похоже, не действует:

my ($i, $j) = ('INIT', 'INIT'); 

foreach $i (1..10){
    $temp = $i+1;
}

print "\nThis is i: $i\n";   # prints 'This is i: INIT'. 



foreach my $j (1..10){
    $temp = $j+1;
}

print "\nThis is j: $j\n";   # prints 'This is j: INIT'. 

Ответы [ 5 ]

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

С http://perldoc.perl.org/perlsyn.html#Foreach-Loops:

Цикл foreach выполняет итерацию по обычному значению списка и устанавливает переменную VAR в качестве каждого элемента списка по очереди. Если переменной предшествует ключевое слово my, то она имеет лексическую область видимости и поэтому видна только внутри цикла. В противном случае переменная неявно является локальной для цикла и восстанавливает свое прежнее значение при выходе из цикла. Если переменная была ранее объявлена ​​с помощью my, она использует эту переменную вместо глобальной, но она все еще локализована в цикле. Эта неявная локализация происходит только в цикле foreach.

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

Ганс связался с документацией, описывающей, как переменная в цикле foreach ограничена. Различие тонкое, но оно может быть важным:

sub f { return $i }
$i = 4;
$m = $n = 0;

foreach    $i (1 .. 10) { $m += f() }
foreach my $i (1 .. 10) { $n += f() }

print "Result with localization:    $m\n";    #  ==>  55
print "Result with lexical scoping: $n\n";    #  ==>  40
1 голос
/ 10 февраля 2010

Одним из самых болезненных открытий в Perl, которое я сделал, было то, что переменная "my" в цикле foreach не является локальной копией. Я был разочарован, обнаружив, что мой массив был уничтожен.

Единственным выходом кажется:


foreach ( @array ) {
  my $element = $_; # make a local copy
  ...
}

Если вы посмотрите на perldoc , в нем говорится: «Индексная переменная цикла foreach является неявным псевдонимом для каждого элемента в списке, над которым вы циклически работаете» и «Если какой-либо элемент LIST является lvalue , вы можете изменить его, изменив VAR внутри цикла ".

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

Итератор в цикле foreach эффективно является локальным для цикла. Тем не менее, он непосредственно содержит значение из списка в том, что фактически является вызовом по ссылке, а не по значению. Таким образом, если вы работаете со значением в цикле, оно изменит значение в списке. Однако переменная итератора определяется только со ссылкой на цикл:

@names = qw(Kirk Spock Bones);

$officer = "Riker";
print "@names $officer\n"; # will print Kirk Spock Bones Riker

foreach $officer (@names) {
     $officer .= "y";
}

print "@names $officer\n"; # will print Kirky Spocky Bonesy Riker

Таким образом, итератору, в данном случае $ employee, фактически предшествует 'my' с точки зрения сохранения любого значения, которое он имел до цикла foreach. Однако, если значения, которые он содержит, будут изменены, это изменение вернется в список, по которому вы перебираете.

0 голосов
/ 10 февраля 2010

Я только что провел дополнительное исследование по этой интересной проблеме.

foreach не волнует, если вы сделаете "мой $ y;"до цикла тоже.Итератор по-прежнему будет меняться только в области видимости:

my $y;
foreach $y (1..10) {}

$ y изменится внутри области видимости foreach, но когда он выйдет, он вернется к тому, что было до цикла.

Я думал, что, возможно, foreach автоматически делает «мой $ y»;до его запуска, поэтому я попробовал строгий режим, но это объяснение не сокращает его, потому что тогда оно все равно требует:

foreach my $y (1..10) {}

вместо:

foreach $y (1..10) {}

...что может показаться ненужным, если «foreach $ y» функционально совпадает с «foreach my $ y».

...