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