【问题标题】:How to create an anonymous array ([]) with 'empty slots'?如何使用“空槽”创建匿名数组([])?
【发布时间】:2011-07-03 22:09:52
【问题描述】:

我可以创建一个包含“空槽”的数组:

$ perl -wde 1
...
  DB<1> $x[2] = 0
  DB<2> x \@x
0  ARRAY(0x103d5768)
   0  empty slot
   1  empty slot
   2  0

  DB<3> $#y = 4
  DB<4> x \@y  
0  ARRAY(0x103d5718)
   0  empty slot
   1  empty slot
   2  empty slot
   3  empty slot
   4  empty slot

请注意:这与分配undef 不同。

但是如何使用[] 为匿名数组指定呢?

这不起作用:

  DB<5> x [,,0]
syntax error at (eval 27)[/usr/local/lib/perl5/5.10.0/perl5db.pl:638] line 2, near "[,"

这也失败了,因为我只得到了分配的值:

  DB<6> x []->[2] = 0
0  0

额外问题:如何在我的 Perl 脚本中检查“空数组槽”?

背景:在我的测试脚本中,我希望能够精确地比较数组内容。例如,我想区分“未分配”和“使用 undef 值分配”。

感谢您提供任何见解。

【问题讨论】:

  • 你的意思是如何直接分配给一个数组,使用[] 匿名数组,在使用exists 测试时数组内部的值返回false?
  • 是的。懒惰,能够在一个语句中指定这一点会很好。否则我必须使用“undef”或在多个语句中使用。

标签: perl anonymous-arrays


【解决方案1】:
use feature qw/ say /;
use strict;
use warnings;

my $aref;

$#{$aref} = 4;
$aref->[2] = undef;
$aref->[3] = '';

foreach my $idx ( 0 .. $#{$aref} ) {
    say "Testing $idx.";
    say "\t$idx exists." if exists $aref->[$idx];
    say "\t$idx defined." if defined $aref->[$idx];
}

OUTPUT:
Testing 0.
Testing 1.
Testing 2.
    2 exists.
Testing 3.
    3 exists.
    3 defined.
Testing 4.

我们在匿名数组@{$aref} 中预先分配了五个位置。顶部索引是4。我们能够以与我们创建它的方式相同的方式找到顶部索引;通过测试$#{$aref} 的值。我们可以测试存在。我们知道04 之间的所有内容都已创建。但是 Perl 只报告特定分配给它们的数组元素的“存在”(即使它是 undef)。因此,$aref-&gt;[2] 被报告存在,但未定义。只是为了好玩,我们将'' 分配给$aref-&gt;[3] 以查看定义一次的测试报告。但简而言之,即使数组是预扩展的,我们仍然可以通过使用 '@987654333 来测试使用 undef 初始化的元素和通过数组预扩展为 undef 的元素之间的区别@'。

我不能说这是exists 的记录行为。所以不能保证有一天它不会改变。但它适用于 5.8、5.10、5.12 和 5.14。

因此,寻找一种简单的方法来查找哪些元素已初始化,哪些已定义,哪些未定义,这里有一个示例:

use feature qw/ say /;
use strict;
use warnings;

my $aref;

$#{$aref} = 4;
$aref->[2] = undef;
$aref->[3] = '';

my @initialized = grep { exists $aref->[$_] } 0 .. $#{$aref};
my @defined = grep { defined $aref->[$_] } 0 .. $#{$aref};
my @uninitialized = grep { not exists $aref->[$_] } 0 .. $#{$aref};
my @init_undef = grep { exists $aref->[$_] and not defined $aref->[$_] } 0 .. $#{$aref};
say "Top index is $#{$aref}.";
say "These elements are initialized: @initialized.";
say "These elements are not initialized: @uninitialized.";
say "These elements were initialized with 'undef': @init_undef.";
say "These elements are defined: @defined."

【讨论】:

  • 非常感谢!我的第二个问题的好答案!与此同时,我发现delete $aref-&gt;[2]; 变回“未初始化”,就像它对哈希条目所做的那样。
  • 很高兴您发现它有帮助。解决这些难题总是很有趣。
【解决方案2】:

应该这样做:

$a=[];
$#$a=4;

更新(回复@hexcoder):在一个声明中:

$#{$a=[]}=4

在一个返回数组的语句中:

$a = (map(($_,$#$_=4),[]))[0]

虽然,我不推荐使用那种结构...

【讨论】:

  • 我同意,同样$a=[]; $a-&gt;[2] = 0; 也应该这样做。但是有可能在一个声明中吗?可能不是没有任何模块的支持。
【解决方案3】:

背景:在我的测试脚本中,我希望能够精确地比较数组内容。例如,我想区分“未分配”和“使用 undef 值分配”。

您可以检查索引是否超过末尾。除此之外,您无能为力。

$x = [];
undef $x->[9999];
print scalar @$x;

打印 10000。undef $x-&gt;[9999] 等价于 $x-&gt;[9999] = undef; 因为不存在 0 到 9998 的元素,perl 会神奇地将所有中间元素分配给 undef

【讨论】:

  • 谢谢。我不同意perl will magically assign all of the intervening elements to undef。正如您在我的第一个调试输出孔中看到的那样,显示为“空槽”。如果它们被分配“undef”,调试器将在此处显示“undef”。我已经尝试过了,但没有在问题中显示。
  • @hexcoder:这是因为虽然它们的值没有定义,但它们没有 undef 作为值。奇怪的细微差别。
  • @DavidO:是的。在调试器中x @xx \@x 之间存在差异。第一个将显示“undef”,第二个将显示“空槽”。 p @x 会针对未初始化的值给出警告。
【解决方案4】:

您只能通过 XS 代码执行此类操作(例如,请参阅 Devel::Peek)。 *::Util 包暴露了其中的一些,但不是全部。 (我一直在研究调试/跟踪包,所以我对此的了解比任何人都需要的多......)

【讨论】:

  • 感谢您的指点。我会看一看。太糟糕了,没有直接的 Perl 方法(我认为有不止一种方法可以做到这一点;-)。
  • 我在 ::Util 中找不到任何有用的东西。我希望 List::*Util 或 Array::Utils 中有一些东西,但什么也没有。你能说得更具体点吗?
猜你喜欢
  • 2010-12-26
  • 2011-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-06
  • 1970-01-01
  • 2013-05-08
  • 1970-01-01
相关资源
最近更新 更多