Подтвердить что ты не робот

Какова стандартная область цикла foreach в Perl?

В Perl, использует ли "мой" внутри цикла foreach какой-либо эффект? Кажется, что индексная переменная всегда локальна, используется ли "мой" . Итак, можете ли вы оставить "мой" в цикле 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'. 
4b9b3361

Ответ 1

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

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

Ответ 2

Ханс связан с документацией, описывающей, как переменная в цикле 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

Ответ 3

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

Кажется, что единственный способ:


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

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

Ответ 4

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

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

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

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

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

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

в отличие от:

foreach $y (1..10) {}

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

Ответ 5

Итератор в цикле 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

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