面向对象的perl,设置哈希值



我有一个类:

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的值。当

中没有传递任何信息时,我们也可以将这个子节点作为getter
sub 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)。

请注意,还有更紧凑的方法来处理键/值列表。

最新更新