我有一个类:
sub new {
my ($class, $name) = @_;
my $self = {
_ids => [],
_devices => {}
};
bless ($self, $class);
return $self;
}
我向子程序传递一个数组,并说:
sub Importids {
my ($self, $id_ref) = @_;
foreach $id (@{$id_ref})
{
push(@{$self->{_ids}}, $id);
}
}
我还想在这个函数中添加初始化哈希值的功能,但是这样做很费时间。最后,我希望我的哈希值看起来像这样,用于多个id:
_device --> id1|
--> status --> 0/1
id2|
--> status --> 0/1
,其中id为键。
我尝试在函数中这样做:
sub Importids {
my ($self, $id_ref) = @_;
foreach $id (@{$id_ref})
{
push(@{$self->{_ids}}, $id);
}
foreach my $id_value(@{$self->{_ids}})
{
$self->{_devices}{$id_value}{'status'} = 0;
}
}
但是当我像下面这样检查内容时,它只返回哈希值
的十六进制转储for my $hash_key (keys %{$self->{_devices}})
{
print $self->{_devices}{$hash_key};
#print keys % {$self->_devices}};
}
给:
HASH(0x....)
HASH(0x....)
...
...
HASH(0x....)
然而,当我尝试:
for my $hash_key (keys %{$self->{_devices}})
{
print $self->{_devices}->{$hash_key}->{'status'};
}
我得到了我想要的:
0
0
...
0
我应该如何访问键并添加额外的字段,如status2 " ?
注释简短的第一部分是指原问题,同时发生了变化。
设置哈希时,使用$id_value
作为变量,用id遍历数组。然后将它分配给一个不存在的键
$self->{_devices}{ids} = $id_value; # what is 'ids' string?
因此,将添加一个键'ids'
,并且每个赋值将覆盖前一个赋值。另外,请注意,这样$id_value
(将)成为值,而不是键,与问题所陈述的相反。
在$self->{_devices}
中应该是什么?如果键是id,要"初始化"";",说到0
foreach my $id (@$id_ref)
{
push @{$self->{_ids}}, $id;
$self->{_devices}{$id} = 0;
}
有更紧凑和更清晰的方法,但让我们首先澄清这是否是有意的。
更新注释中的澄清
目标是构造一个结构 <>之前_device——> id1——> status——> 0/1Id2——> status——> 0/1…之前我们还希望能够读取/更改值,并添加另一种"状态"。让我们先忘掉类,构建这个数据结构。参见教程perlreftut和数据结构烹饪书perlreftut。
在Perl中,我们可以使用哈希引用来实现这一点,并进一步嵌套哈希引用
my $hashref = {
'id1' => {
'status' => 0,
'status2' => 0
},
'id2' => {
'status' => 0,
'status2' => 0,
},
# ...
};
匿名散列 { status => 0, status2 => 0 }
作为值分配给密钥'id1', 'id2'
。作为对散列的(无名)引用,它被松散地称为hashref(就像%hash
一样)。任何引用都是一个标量,一个单个值,因此可以将hashref分配给键。这就是我们如何使用引用来构建嵌套的(复杂的)数据结构。它们很像指针。
我们可以像这样在代码中填充它
use warnings 'all';
use strict;
use Data::Dumper; # to see our structures
my @ids = qw(id1 id2 id3);
my $hashref;
foreach my $id (@ids) {
foreach my $stat ('status', 'status2') {
$hashref->{$id}{$stat} = 0;
}
}
print Dumper($hashref);
严格地说,我们需要在$hashref->{$id}->{$stat}
的每一层解引用,但是一个符号快捷方式允许我们省略除第一个之外的所有内容(因为那不可能意味着任何其他内容)。
键$id
一旦遇到(autovivified)就被添加到哈希中。嵌套散列(ref)中的键$stat
也是如此(上面赋值为0
)。我们通过
$hashref->{$id}{'status'} = 1;
print "$hashref->{$id}{'status'}n";
我们可以用同样的方式添加另一个'status', $hashref->{$id}{'status3'} = 0
。
现在进入课堂。我们只使用一个"状态"字段。请添加适当的错误检查
sub Importids
{
my ($self, $id_ref) = @_;
foreach my $id (@{$id_ref})
{
push @{$self->{_ids}}, $id;
$self->{_devices}{$id}{'status'} = 0;
}
return 1;
}
如何更改给定id的值?我们先来设计一个界面。使用$id
变量中的id和$val
变量中的新值,我们可以想象调用
$obj->set_status( { $id1 => $val1, $id2 => $val2 } );
# Or
$obj->set_status( $new_vals_for_ids_hashref );
在调用内部构建一个hashref或使用先前构建的hashref。下面是它的一个方法
sub set_status
{
my ($self, $rhstat) = @_; # check for $rhstat
foreach my $id (keys %$rhstat) {
$self->{_devices}{$id} = $rhstat->{$id};
}
return 1;
}
如果id不存在,则添加新id,或者覆盖现有id的值。当
中没有传递任何信息时,我们也可以将这个子节点作为gettersub status
{
my ($self, $rstat) = @_;
return $self->{_devices} if not defined $rstat;
foreach my $id (keys %$rstat) {
$self->{_devices}{$id} = $rstat->{$id};
}
return $self->{_devices};
}
使用my $devices = $obj->status();
或带参数。因为我们现在在一种情况下返回数据,所以当添加/更改id时,我们也会这样做,以保持接口一致性。
你可以类似地添加'status'字段,
$obj->add_status( [ qw(status2 status3) ] );
其中[ ... ]
是一个匿名数组,带有一个方法
sub add_status
{
my ($self, $rstats) = @_;
foreach my $stat (@$rstats)
{
foreach my $id (@{$self->{_ids}})
{
$self->{_devices}{$id}{$stat} = 0;
}
}
return 1;
}
可以通过传递一个带有键值对(添加键并设置键值)的hashref, 或一个如上所述的arrayref,使该方法也可以选择性地获取和设置新键值(参见ref)。
请注意,还有更紧凑的方法来处理键/值列表。