在仅使用一种数据结构时,有没有办法执行以下操作?
my %hash = (
"key1" => "value1",
"key2" => "value2",
"key3" => $hash{key1},
);
基本上,我想将哈希的键值设置为另一个键值。我已经尝试了上面的语法,但得到以下警告:
Global symbol "%hash" requires explicit package name at ...
我假设这是因为我试图在实际创建之前引用哈希。
答案 0 :(得分:10)
这是因为,在使用$hash{key1}
时,符号“hash”尚未添加到符号表中。你的包还不知道%hash
是什么,因为在解析结束“)之前它不会被添加到符号表中 - 但它会更早地遇到符号1行。
您需要提前预先声明%hash:
my %hash;
%hash = (
"key1" => "value1",
"key2" => "value2",
"key3" => $hash{key1},
);
但是,虽然上面将编译,它将无法按预期工作,因为在评估%hash
时尚未为$hash{key1}
分配任何内容。您需要先将其分配,作为单独的声明:
my %hash;
%hash = (
"key1" => "value1",
"key2" => "value2",
);
%hash = %hash, (
"key3" => $hash{key1},
); # Or simply $hash{key3} = $hash{key1};
请注意,上述仅将值从key1
复制到key3
,一次。之后他们绝不会联系/关联。如果您想要别名key1
和key3
(例如将它们指向指向相同的值,而不是包含该值的副本),这可能但不会像不重要的。您需要将其设置为绑定哈希并编写自定义绑定处理程序以使其正确,或者使每个键的值为引用。
答案 1 :(得分:4)
如果您希望$ hash {key1}成为$ hash {key3}的别名,那么可以使用Data::Alias轻松完成此操作。
use Data::Alias;
my %hash = (
key1 => 'value1',
key2 => 'value2'
);
alias $hash{key3} = $hash{key1};
$ hash {key1}和$ hash {key3}现在将引用单个值,并且对另一个的更新将在另一个中可见。
答案 2 :(得分:2)
您可以使用核心模块Hash::Util
来访问低级hv_store
例程,该例程可以将哈希值合并在一起。 1}}并不像使用Data::Alias
一样整洁,但它已经安装好了。
use Hash::Util 'hv_store';
my %hash = (
key1 => "value1",
key2 => "value2",
);
hv_store %hash, key3 => $hash{key1};
say "$_: $hash{$_}" for sort keys %hash;
# key1: value1
# key2: value2
# key3: value1
$hash{key1} = 'new value';
say "$_: $hash{$_}" for sort keys %hash;
# key1: new value
# key2: value2
# key3: new value
如果你不希望别名在初始赋值之后保持不变,那么你可以写下这一行:
$hash{key3} = $hash{key1}
在您的初始声明之后并跳过使用hv_store
。
答案 3 :(得分:1)
%hash
在创建要分配给哈希值的值列表时不包含任何内容,因为您还没有将列表分配给哈希值。
事实上,%hash
在创建要分配给哈希值的值列表时不存在,因为赋值会在其LHS之前评估其RHS。这就是您遇到严格错误的原因。
您可能会喜欢的一些解决方案:
my %hash = (
key1 => "value1",
key2 => "value2",
key3 => "value1",
);
my $value1 = "value1";
my %hash = (
key1 => $value1,
key2 => "value2",
key3 => $value1,
);
my %hash = (
( map { $_ => "value1" } qw( key1 key3 ) ),
key2 => "value2",
);
答案 4 :(得分:1)
为什么不自己动手:
use strict;
use warnings;
sub make_hash (@) {
my %h;
my @unresolved;
while ( @_ ) {
my ( $key, $value ) = splice( @_, 0, 2 );
next unless defined $value;
if ( not ref( $value )
and my ( $ref ) = $value =~ /^ref:\s*(.*\S)\s*$/
) {
if ( defined( my $v = $h{ $ref } )) {
$h{ $key } = $v;
}
else {
push @unresolved, [ $key, $ref ];
}
}
else {
$value =~ s/^lit://;
$h{ $key } = $value;
}
}
$h{ $_->[0] } = $h{ $_->[1] } foreach grep { exists $h{ $_->[0] }; } @unresolved;
return wantarray ? %h : \%h;
}
展示一些力量:
my %hash
= make_hash(
'key1' => 'value1'
, 'key2' => 'value2'
, 'key3' => 'ref:key1'
, 'key4' => 'lit:ref:key2'
, 'key5' => 'lit:lit:ref:key3'
);
lit:
前缀涵盖“如果我真的想要将非引用的值传递为'ref:so-and-so'
的情况?它也是递归的回答,“如果我迫切需要使一个值'点亮:xzy'怎么办?
我已经完成了这项工作,并且我也祝福了对Lit
类的传递数据或类似内容的引用。
sub Ref ($) { bless \shift, 'Ref' }
然后在make_hash
例程中,您只需检查ref( $value ) eq 'Ref'
。并指定如下:
my %hash
= make_hash(
'key1' => 'value1'
, 'key2' => 'value2'
, 'key3' => Ref 'key1'
);
有很多方法可以让Perl像你希望的那样行事。
答案 5 :(得分:0)
你可以说
my %h;
my $i = 0;
while (
my ( $k, $v ) = (
key1 => '"value1"',
key2 => '"value2"',
key3 => '$h{key1}',
)[ $i, $i + 1 ]
)
{
$h{$k} = eval $v;
$i += 2;
}
只要引用的任何键在引用之前出现在列表中。