Какова стандартная область цикла 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'.
Ответы
Ответ 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. Однако, если значения, которые он имеет, будут изменены, это изменение вернется к списку, который вы выполняете.