数组与列表引用问题

时间:2011-02-15 19:56:29

标签: perl

关于以下代码的两个问题:


%h1 = {
    'key1' => ( 1, 2, 3 ),
    'key2' => ( 4, 5, 6 )
    };

%h2 = {
    'key1' => [ 1, 2, 3 ],
    'key2' => [ 4, 5, 6 ]
    };

print $(@h1{'key2'})[1];

Q1:h1和h2有什么区别?请不要说'一个是列表的哈希和另一个数组的哈希'...相反,我想知道在使用方面的转换。

Q2:为什么print语句中的引用$(@h1{'key2'})[1]不能编译?这是我的想法:我想访问与'key2'对应的数组/列表:@h1{'key2'}。然后我想访问该列表/数组中索引1处的标量:$(@h1{'key2'})[1]。为什么这是错的?这个变量引用的东西很混乱。

4 个答案:

答案 0 :(得分:14)

这些都不像你想的那样工作。使用严格并始终使用警告。

%h1 = {
'key1' => ( 1, 2, 3 ),
'key2' => ( 4, 5, 6 )
};

您正在尝试将hashref({}构造)分配给哈希。它被字符串化为标量,并在%h1中用作键,值为undef。另外,因为你正在使用列表(()构造),它会变得扁平,你正在创建哈希:

%href = ( key1 => 1,
          2 => 3,
          key2 => 4,
          5 => 6,
        );

在后一种情况下,您使用数组引用([]构造)正确创建哈希,但您仍然在为哈希分配href。你想做的事:

%h1 = (
'key1' => [ 1, 2, 3 ],
'key2' => [ 4, 5, 6 ]
);

这会在列表上下文中创建%h1,并通过引用在标量上下文中创建值。

答案 1 :(得分:6)

区别:他们都错了! :)

列表是扁平结构;你不能有列表列表,你只需要一个(一维)列表。

参考文献是标量。所以%h1 = { ... }没有意义。你正在做的只是将一个元素列表分配给%h1,它被字符串化并变成一个键。这相当于

%h1 = ( 'HASH(0x1fb872a0)' => undef );

其中键是保存该哈希引用的任何内存地址的字符串化版本。

要制作数组哈希,请执行以下操作:

my %h1 = ( key1 => [ 1, 2, 3 ], key2 => [ 4, 5, 6 ] );

如果要引用数组哈希,可以使用:

my $ref = { key1 => [ 1, 2, 3 ], key2 => [ 4, 5, 6 ] };

my $ref = \%h1;

最后,要访问您的结构元素,您可以使用:

print $h1{key2}[1];

print $ref->{key2}[1];

在后一种情况下,我们使用->运算符取消引用结构。对于后续级别,假定为->,但您也可以编写

print $ref->{key2}->[1];

如果你发现更清楚。

要从参考中获取完整的结构(例如使用keys),您需要使用其他形式的解除引用:

my @keys = keys %$ref;    # or more explicitly %{ $ref }

为了获得完整的内部结构,它是一样的:

my @a2 = @{ $ref->{key2} };

以下优秀的Perl文档详细介绍了所有这些内容:

  1. Perl references tutorial
  2. Perl references
  3. Perl data structures cookbook
  4. 和其他人。

答案 2 :(得分:5)

区别在于%h1分配完全错误且%h2分配几乎正确。

Perl使用括号创建列表,可以将其分配给数组或散列:

@a = (1, 2, 3);
%a = (foo => 'bar', 7 => 3);

Perl使用括号创建列表引用,可以将其分配给标量。

$a = [ 1, 2, 3 ];

Perl使用大括号创建哈希引用,可以将其分配给标量。

$a = { key1 => 1, key2 => 2 };

要记住的另一个要点是哈希表的值总是标量。 Perl中没有“散列哈希”列表的“哈希” - 这些是方便的术语,实际上意味着“列表引用的哈希”和“哈希哈希引用”。

考虑到这一点,让我们看看你的例子:

%h1 = { ... };

已经错了。大括号创建一个哈希引用,它被视为单个标量,你正在做的就是这个:

$scalar = { ... };
%h1 = ( "$scalar" => undef );

所以%h1包含一个名为HASH(0x54321098)的丑陋名称而不是您的意思。相反,说

%h1 = ( ... )

继续前进,

%h1 = (
'key1' => ( 1, 2, 3 ),
'key2' => ( 4, 5, 6 )
);

也不会做你想做的事情。在这个赋值中有列表,而不是列表引用,另外要记住的是Perl“扁平化”列表。如果你认为=>和逗号的同义词一样(几乎是真的),那么你会看到这个赋值相当于:

%h1 = ( 'key1', 1, 2, 3, 'key2', 4, 5, 6 );

%h1 = ( 'key1' => 1,
        2 => 3,
        'key2' => 4,
        5 => 6 );

创建一个包含四个键值对的哈希表,而不是您期望的那两个。

如果我们修复%h2作业周围的大括号,那么

%h2 = ( key1 => [ 1, 2, 3 ],
        key2 => [ 4, 5, 6 ] );

会做你期望的。请记住,哈希表的值必须是标量,并且列表引用是标量。然后,您可以说出$h2{'key1'}[1]之类的内容来获取各个列表元素(在本例中为2)。

答案 3 :(得分:1)

如果编译%h1是关联数组

( 'HASH=(...)' => undef )

由于您传递的是数组引用而不是键值对列表。

如果%h1的表达式有效,则文字哈希值为:

{ key1 => 1, 2 => 3, key2 => 4, 5 => 6 }

就像你创建它一样:

my%h1 =(key1 => 1,2 => 3,key2 => 4,5 => 6);

无论括号如何,它都会一起处理每个列表。

因此,您将解除引用'4'(或'1')作为数组 - 当然您当前正尝试取消引用undef

但是有可能像这样构建它,当你@h1{'key2'}时,你得到一个列表 ( '4' ),如果在标量上下文中进行评估,则变为'1' < / p>

即使$h1{'key2'}指向数组@h1{'key2'},您也会( [ 4, 5, 6 ] )而不是( 4, 5, 6 )