“pre-increment” $#array 是什么意思?

5

我遇到了以下这行代码。它存在一些问题:

  • 本意是执行push的操作
  • 应该使用push才对
  • 很难读懂、理解
  • 我已经改为使用push
  • 它执行了我认为非法的操作,但显然不是

代码如下:

$array [++$#array] = 'data';

我的问题是:什么意思是预增加$#array?我一直认为$#array是数组的一个属性,不可写入。

感谢您的编辑 - 那就是我应该写的标题。 - Paul Beckingham
5个回答

14

perldata 表示:

"数组的长度是一个标量值。您可以通过计算 $#days 来查找数组 @days 的长度,就像在 csh 中一样。然而,这不是数组的长度;它是最后一个元素的下标,由于通常存在第0个元素,因此这是一个不同的值。实际上,将值分配给 $#days 会更改数组的长度。这种方式缩短数组会破坏中间的值。之前被缩短的数组增加长度并不能恢复那些元素中的值。"

在某些情况下修改 $#array 是有用的,但在这种情况下,显然使用 push 更好。


当你事先知道数组最终的大小时,其中一个情况使用它会更好。对于大型数组而言,这将大幅提升性能。 - innaM
在旧版本的Perl中,使用$#array进行长度延长会返回先前的值。 - Brad Gilbert

4

后置递增会先返回变量再将其递增。

如果你使用后置递增,你将修改最后一个元素,因为它首先被返回,然后将一个空元素推到末尾。在第二个循环中,您将修改该空值并推送一个新的空值以供以后使用。所以它根本不像推送。

前置递增将递增变量,然后再返回它。这样,您的示例始终会写入数组的新的、最后一个元素,并像推送一样工作。以下是示例:

my (@pre, @post);

$pre[$#pre++] = '1';
$pre[$#pre++] = '2';
$pre[$#pre++] = '3';


$post[++$#post] = '1';
$post[++$#post] = '2';
$post[++$#post] = '3';

print "pre keys: ".@pre."\n";
print "pre: @pre\n";
print "post keys: ".@post."\n";
print "post: @post\n";

输出:

pre keys: 3
pre: 2 3
post keys: 3
post: 1 2 3

“return”值的增量运算符是一个重要的区别,我很高兴有人指出了它。 - jettero

4
将大于当前数组长度的值赋给$#array会扩展数组。

我认为这个链接是一本未经授权的书的副本。我建议你将其删除。 - mirod
实际上,链接已经失效了,但我同意链接盗版书籍是一个坏主意。 - Telemachus
当我检查它时,它并没有死掉,而且那里还有许多其他的书。 - mirod
欢迎来到互联网。为什么曼努因通过 Google 找到的链接而被惩罚呢? - jrockway
虽然这些盗版副本很烦人,但它们几乎不会破坏我们的业务......许多侵权者对一封礼貌的信件做出回应。那些忽略我们请求的服务器通常位于图书不可得或者价格过高的国家。——某个名叫 Tim 的人 :) - ysth
显示剩余2条评论

3

这段代码也可以运行:

$ perl -le 'my @a; $a[@a]="Hello"; $a[@a]=" world!"; print @a'
Hello world!

Perl数组是动态的,当超出限制时可继续增长。


我不明白 ++$#array 怎么可能没有改变它。我假设在赋值之后,$#array 再次被修改,可能是相同的值。 - Paul Beckingham
我认为在这里使用 ++$#array 是无用的。 - Hynek -Pichi- Vychodil
如果您使用$#array,您只会覆盖数组的最后一个元素(或者如果数组为空,则会出现“尝试修改不可创建的数组值,下标为-1”的错误)。因此,您确实需要++$#array。 - mirod
预增量的写回部分确实是无用的,但是必须进行+1操作才能计算出正确的数组索引(如果您真的非常想通过下标访问数组而不是推送)。顺便说一句,++很容易输入。那么对于额外的混淆,如何使用$a[@a] = 1? - JB.
1
多么奇怪的代码: @a[--$|+$#a]=$_ for 0..9; print @a - ysth

1
首先,这很糟糕。
话虽如此,我也很惊讶它能工作。我本以为 ++$#array 会得到“无法修改常量”的错误,这是当尝试增加数字时得到的错误。(当然,我从来没有不小心做过这种事)。但是,我想我们错了: $#array 不是一个常量(一个数字);它是一个变量表达式。因此,您可以对其进行更改。请考虑以下内容:
my @array = qw/1 2 3/;

++$#array;
$array[$#array] = qw/4/;

print "@array\n"

甚至,为了更多的乐趣,还有这个:

my @array = qw/1 2 3/;

$#array += 5;

foreach my $wtf (@array) {
  if (defined $wtf) {
    print "$wtf\n";
  }
  else {
    print "undef\n";
  }
}

是的,Perl Cookbook很高兴通过操作$#array来增加或缩小数组(第4章,第3个配方)。我仍然觉得它很丑陋,但也许这只是一种持久的“但它是一个数字”的偏见。


我不确定你的想法,但是认为它很丑,因为它有4个标点符号,它们不是分隔符或括号,并排在一起...我的意思是,我也认为a = b + (foo ?-$#array:+$#array);很丑B-) - Brian Postow

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接