为什么Perl foreach变量赋值修改数组中的值?

tst*_*ter 18 perl

好的,我有以下代码:

use strict;
my @ar = (1, 2, 3);
foreach my $a (@ar)
{
  $a = $a + 1;
}

print join ", ", @ar;
Run Code Online (Sandbox Code Playgroud)

和输出?

2,3,4

有没有搞错?为什么这样做?这总是会发生吗?是$ a不是一个真正的局部变量?他们在想什么?

Ano*_*on. 25

Perl有很多这些几乎奇怪的语法事物,它们大大简化了常见任务(比如迭代列表并以某种方式更改内容),但是如果你不了解它们就可以绊倒你.

$a别名为数组中的值 - 这允许您修改循环内的数组.如果您不想这样做,请不要修改$a.


Sin*_*nür 22

perldoc perlsyn:

如果LIST的任何元素是左值,您可以通过修改循环内的VAR来修改它.相反,如果LIST的任何元素不是左值,则任何修改该元素的尝试都将失败.换句话说,foreach循环索引变量是您循环的列表中每个项的隐式别名.

尽管我发现有多少人在遇到他们不理解的行为时拒绝检查文档,但没有什么奇怪奇怪记录语言功能.

  • 为什么即使记录下来也不会被认为是奇怪的东西.如果语言规范说返回语句之后的单个语句将被执行,但不超过1,那会怎么样.这既奇怪又有记录.奇怪的是意见问题. (16认同)
  • 为"我觉得很奇怪有多少人拒绝阅读任何文档"+1.:-P (4认同)

Chr*_*ung 9

$a在这种情况下是数组元素的别名.只是没有$a =你的代码,你不会修改数组.:-)

如果我没有记错,map,grep等方面都有着相同的混叠行为.


dao*_*oad 5

正如其他人所说,这是记录在案的。

我的理解是@_formap和的混叠行为grep提供了速度和内存优化,并为创意提供了有趣的可能性。发生的事情本质上是构造块的传递引用调用。这样可以避免不必要的数据复制,从而节省时间和内存。

use strict;
use warnings;

use List::MoreUtils qw(apply);

my @array = qw( cat dog horse kanagaroo );

foo(@array);


print join "\n", '', 'foo()', @array;

my @mapped = map { s/oo/ee/g } @array;

print join "\n", '', 'map-array', @array;
print join "\n", '', 'map-mapped', @mapped;

my @applied = apply { s/fee//g } @array;

print join "\n", '', 'apply-array', @array;
print join "\n", '', 'apply-applied', @applied;


sub foo {
   $_ .= 'foo' for @_;
}
Run Code Online (Sandbox Code Playgroud)

注意List::MoreUtils apply函数的使用。它的工作原理类似于map但复制主题变量,而不是使用引用。如果你讨厌写这样的代码:

 my @foo = map { my $f = $_; $f =~ s/foo/bar/ } @bar;
Run Code Online (Sandbox Code Playgroud)

你会喜欢的apply,这使它变成:

 my @foo = apply { s/foo/bar/ } @bar;
Run Code Online (Sandbox Code Playgroud)

需要注意的事情:如果您将只读值传递到修改其输入值的这些构造之一中,您将收到“尝试修改只读值”错误。

perl -e '$_++ for "o"'
Run Code Online (Sandbox Code Playgroud)