3

这是我正在使用的代码片段:

my %photo_details = (
 'black_cat' => (
  ('size' => '1600x1200', 'position' => -25),
  ('size' => '1280x1024', 'position' =>  25),
  ('size' =>   '800x600', 'position' =>   0),
 ),
 'race_car' => (
  ('size' => '1600x1200', 'position' =>  10),
  ('size' =>   '800x600', 'position' =>   5),
 ),
);

my $photo = 'black_cat';

foreach my $photo_detail ($photo_details{$photo})
{
 my $size     = $photo_detail{'size'};
 my $position = $photo_detail{'position'};

 print ("size = $size, position = $position\n");
}

我期望得到的是:

大小 = 1600x1200,位置 = -25

大小 = 1280x1024,位置 = 25

大小 = 800x600,位置 = 0

我得到的是:

在 C:\Test.pl 第 23 行的连接 (.) 或字符串中使用未初始化的值 $size。

在 C:\Test.pl 第 23 行的连接 (.) 或字符串中使用未初始化的值 $position。

大小 = , 位置 =

foreach 语句显然是错误的,因为不仅没有 $size 和 $position 的值,而且它只经历了一次循环而不是三次。我已经尝试了各种变量前缀的变体,但都没有找到。

我究竟做错了什么?

4

3 回答 3

14

首先,始终以以下方式启动每个脚本或模块:

use strict;
use warnings;

您将更快地收到更多警告消息,这对调试有很大帮助。

我无法复制您的错误:当我将该代码放入文件并在没有其他标志的情况下运行它时,我得到:size = , position =. 您打印的代码中没有$size变量,因此错误消息不匹配。

然而,您错误地声明了您的数据结构。散列和数组只能包含标量值,不能包含列表:因此,如果要嵌套数组或散列,则需要将其设为引用。有关数据结构和引用的更多信息,请参阅perldoc perldataperldoc perldscperldoc perlreftut

my %photo_details = (
    black_cat => [
        { size => '1600x1200', position => -25 },
        { size => '1280x1024', position =>  25 },
        { size => '800x600', position => 0 },
    ],
    race_car => [
        { size => '1600x1200', position =>  10 },
        { size => '800x600', position =>   5 },
    ],  
);

foreach my $photo_detail (@{$photo_details{black_cat}})
{
    my $size     = $photo_detail->{size};
    my $position = $photo_detail->{position};

    print ("size = $size, position = $position\n");
}
于 2010-01-03T03:03:02.147 回答
14

这是一些更新的代码,下面有解释:

#!/usr/bin/perl

use strict;
use warnings;

use Data::Dumper;

my %photo_details = (
    'black_cat' => [
        {'size' => '1600x1200', 'position' => -25},
        {'size' => '1280x1024', 'position' =>  25},
        {'size' =>   '800x600', 'position' =>   0},
    ],
    'race_car' => [
        {'size' => '1600x1200', 'position' =>  10},
        {'size' =>   '800x600', 'position' =>   5},
    ],
);


print Dumper( %photo_details );
foreach my $name ( keys %photo_details ) {
    foreach my $photo_detail ( @{ $photo_details{$name} } ) {
        my $size     = $photo_detail->{'size'};
        my $position = $photo_detail->{'position'};

        print Dumper( $photo_details{$photo} );

        print ("size = $size, position = $position\n");
    }
}

我已经用方括号和大括号替换了你的一些括号。在 Perl 中,方括号表示对匿名数组的引用,而大括号表示对匿名哈希的引用。这些被称为匿名是因为匿名数组或散列没有明确的变量名。

由于 Perl 数据结构让您存储对哈希的引用而不是实际的哈希,因此您需要这些来构造引用。您可以通过以下两个步骤执行此操作:

my @array = ( 1, 2, 3 );
my $array_ref = \@array;
my %hash = ( 'one' => 1, 'two' => 2, 'three' => 3 );
my $hash_ref = \%hash_ref;

要从 $array_ref 和 $hash_ref 中获取数据,您需要 -> 运算符:

print $array_ref->[0], "\n";
print $hash_ref->{one}, "\n";

引用哈希键时,您不需要在 {} 中使用引号,尽管有些人认为哈希键上的引号是一种很好的做法。

我添加了一个对整个数据结构进行迭代的示例作为示例,而不仅仅是查看一个参考。这是第一行:

foreach my $name ( keys %photo_details ) {

keys 方法返回哈希中的所有键,以便您可以按顺序获取它们。下一行遍历 %photo_details 中的所有 photo_detail hashrefs:

    foreach my $photo_detail ( @{ $photo_details{$photo} } ) {

@{ $photo_details{$photo} }引用取消引用$photo_details{$photo}到一个数组中,您可以使用 foreach 对其进行迭代。

我添加的最后一件事是调用Data::Dumper,这是一个非常有用的模块,随 Perl 一起分发,可以为您打印出数据结构。这在构建这样的数据结构时非常方便,与其密切相关的表亲Data::Dumper::Simple也是如此。不幸的是,这个模块没有随 Perl 一起发布,但我更喜欢它的输出,因为它包含变量名。

有关如何使用引用构建复杂数据结构的进一步阅读,请查看perlreftut

于 2010-01-03T04:24:11.510 回答
2

您真正需要担心的只有一件事,那就是数据结构的顶层。之后,您只需为每个级别使用正确的索引语法:

如果您有常规哈希,则可以访问所需的键,然后在其后为每个级别排列附加索引:

 %regular_hash = ...;
 $regular_hash{$key}[$index]{$key2};

->如果你有一个引用,你几乎可以做同样的事情,但是你必须从顶级引用之后的带有箭头的初始取消引用开始。之后是相同的索引序列:

 $hash_ref = ...;
 $hash_ref->{$key}[$index]{$key2};

有关所有详细信息,请参阅中级 Perl,其中我们解释了参考语法。

于 2010-01-03T10:08:43.497 回答