这个问题是关于要求对Perl系统中发生的事情进行一些解释,因为我现在编码超过25年并没有隐含地看到这一点。故事来了......
在尝试使用Perl5中的Cyrus::IMAP::Admin
个实例时,我试图获取并打印一个配额列表,导致返回一些奇怪的结构化数据。
my %quotas = $client->listquota(@list[0]);
if ( $client->error ) {
printf STDERR "Error: " . $client->error . "\n";
exit 1;
}
print "root: " . $list[0] . "\n";
foreach my $quota ( keys %quotas ) {
print( $quota, " ", $quotas{$quota}[0], "/", $quotas{$quota}[1], " KiB\n" );
}
这段代码实际上是按照需要打印出像
这样的东西root: user.myuser
STORAGE: 123/4567 KiB
此代码取自Cyrus::IMAP::Shell
读取,类似于:
my %quota = $$cyrref->listquota(@nargv);
foreach my $quota (keys %quota) {
$lfh->[1]->print(" ", $quota, " ", $quota{$quota}[0], "/", $quota{$quota}[1]);
if ($quota{$quota}[1]) {
$lfh->[1]->print(" (", $quota{$quota}[0] * 100 / $quota{$quota}[1], "%)");
}
}
使用$quota{$quota}[0]
时,这段代码对我来说有些愚蠢。在我的例子中,我重新命名了一些变量来拒绝混合使用不同类型但等价命名的变量。
在从Cyrus::IMAP::Admin
获取代码之前,我尝试了解其规范并通过自己编写的代码处理结果。它看起来像这样:
my %quotas = $client->listquota(@list[0]);
if ( $client->error ) {
printf STDERR "Error: " . $client->error . "\n";
exit 1;
}
print "root: " . $list[0] . "\n";
foreach my $quota ( keys %quotas ) {
my @sizes = @quotas{$quota};
print( $quota, " ", $sizes[0], "/", $sizes[1], "\n" );
}
然而,这段代码不起作用,我自己也没有找到任何合理的解释。我的理解是,将最后一个代码示例转移到最初发布的表单中需要将第11行中的赋值源替换为第12行中的用法,并将配额的符号从@
更改为$
我正在尝试获得标量结果最后。最后一个代码是在斜杠之前打印数组引用,之后没有任何内容。因此,我必须修复我的代码才能使其正常工作:
my %quotas = $client->listquota(@list[0]);
if ( $client->error ) {
printf STDERR "Error: " . $client->error . "\n";
exit 1;
}
print "root: " . $list[0] . "\n";
foreach my $quota ( keys %quotas ) {
my @sizes = @quotas{$quota};
print( $quota, " ", $sizes[0][0], "/", $sizes[0][1], "\n" );
}
第12行中的这个额外解除引用是我现在感到困惑的。 为什么@sizes
包含一个数组,在其唯一的第一个元素中存储另一个数组?为了让我感到困惑,我已经在第11行尝试了替代代码,但无济于事。这些测试包括
my @sizes = $quotas{$quota};
(与上面公布的原始代码等效)和
my $sizes = @quotas{$quota};
(因为我不知道为什么)。切换符号似乎根本不会改变赋值的语义。但是使用这个赋值似乎打开了%quotas
中包含的数据结构的不同视图。 在最顶层的代码片段中使用@sizes
匹配$quotas{$quota}
的内容和结构需要哪些符号?
答案 0 :(得分:5)
我相信你想要的就是你的第11行:
my @sizes = @{ $quotas{$quota} };
另外,建议您开始在任何地方使用Data :: Dumper。
E.g。
use Data::Dumper;
print 'Data structure of \%quotas: ' . Dumper(\%quotas) . qq(\n);
这样你可以确定你正在处理什么结构。
答案 1 :(得分:5)
$quotas{$quota}
访问%quotas
中的单个标量元素。 @quotas{$quota}
是一个哈希切片,它从哈希中选择一个元素的列表。
$collection[...]
或$collection{...}
:单个标量元素
my @array = (1, 2, 3, 4);
my $elem = $array[1]; #=> 2
@collection[...]
或@collection{...}
:元素列表
my @array = (1, 2, 3, 4);
my @slice = @array[1, 3]; #=> (2, 4)
%collection[...]
或%collection{...}
:键值列表,除“blead”外不可用。
my @array = (1, 2, 3, 4);
my %kvs = %array[1, 3]; #=> (1 => 2, 3 => 4)
在引用集合中的元素时使用另一个sigil不会取消引用该元素!
现在,单个元素列表@quotas{$quota}
包含什么?它是数组引用 [...]
。
将此项指定给标量时,将在标量上下文中评估列表并提供最后一个元素:
my $sizes = @quotas{$quota};
my $sizes = ([...]);
my $sizes = [...];
[...]
访问该数组引用中的元素,然后看起来像$sizes->[0]
。
当您将其分配给数组时,您创建一个数组,该数组将此数组引用保存为单个元素:
my @sizes = @quotas{$quota};
my @sizes = ([...]);
([...])
访问该数组引用中的元素,然后看起来像$sizes[0][0]
,因为您首先必须获取数组@sizes
内的数组引用。
......顺便说一下,$quotas{$quota}
执行时会发生同样的情况,但原因略有不同。
如果要取消引用数组的数组引用,请使用花括号:
my @foo = @{$array_refernce}
复制内容my $elem = ${$array_reference}[0]
,与$array_reference->[0]
相同。所以你可以做到
my @sizes = @{ $quotas{$quota} };
取消引用数组并将其复制到数组变量。然后,您可以访问$sizes[0]
等元素。