关于以下代码的两个问题:
%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]
。为什么这是错的?这个变量引用的东西很混乱。
答案 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文档详细介绍了所有这些内容:
答案 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 )