foreach my $ var (@list) - $ var это ссылка? - PullRequest
8 голосов
/ 18 июня 2009

Итак, я никогда не знал этого, и я хочу получить некоторые разъяснения по этому поводу. Я знаю, если вы делаете

foreach (@list){

если вы измените $ _ в этом цикле, это повлияет на фактические данные. Но я не знал, что если вы сделали

foreach my $var1 (@list){

Если вы измените $ var1 в цикле, это изменит фактические данные. : - / Итак, есть ли способ перебрать @list, но оставить переменную только для чтения или копию, которая при изменении не изменит значение в @list?

Ответы [ 6 ]

10 голосов
/ 18 июня 2009

$var связывается с каждым элементом по очереди.

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

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

9 голосов
/ 18 июня 2009

Самый простой способ - просто скопировать его:

foreach my $var1 (@list) {
    my $var1_scratch = $var1;

или

foreach my $var1 ( map $_, @list ) {

Но если $ var1 является ссылкой, $ var1_scratch будет ссылкой на то же самое. Чтобы быть действительно безопасным, вы должны использовать что-то вроде Storable :: dclone, чтобы сделать глубокое копирование:

foreach my $var1 ( @{ Storable::dclone( \@list ) } ) {
}

(непроверенные). Тогда вы сможете смело менять $ var1. Но это может быть дорого, если @list - это большая структура данных.

4 голосов
/ 18 июня 2009

Это псевдоним, а не ссылка. Если вы хотите создать свои собственные псевдонимы (кроме for), вы можете использовать Data :: Alias ​​.

2 голосов
/ 18 июня 2009

Единственная разница между этими циклами:

foreach (@array) { ... }
foreach my $var (@array) { ... }

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

В простом (и обычном) случае вы можете отключить псевдоним, сделав копию:

foreach my $var (@array) {
    my $copy = $var;
    # do something that changes $copy
}

Это работает для обычных скалярных значений. Для ссылок (или объектов) вам потребуется сделать глубокую копию, используя Storable или Clone , что может быть дорогостоящим. Связанные переменные также проблематичны, perlsyn рекомендует полностью избегать ситуации.

1 голос
/ 18 июня 2009

Я не знаю, как заставить переменную быть по значению вместо по ссылке в самом операторе foreach. Вы можете скопировать значение $_.

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

use Data::Dumper;

my @data = (1, 2, 3, 4);

print "Before:\n", Dumper(\@data), "\n\n\n";

foreach (@data) {
    my $v = $_;
    $v++;
}

print "After:\n", Dumper(\@data), "\n\n\n";

__END__
0 голосов
/ 10 сентября 2011

Сделайте копию @list в операторе for:

foreach my $var1 (() = @list) {
  # modify $var without modifying @list here
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...