【问题标题】:object oriented perl, set hash values面向对象的perl,设置哈希值
【发布时间】:2021-04-30 15:59:01
【问题描述】:

我有一堂课:

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''?

【问题讨论】:

  • 这里print $self->{_devices}{$hash_key};正在打印 hashref。这里$self->{_devices}->{$hash_key}->{'status'};,和$self->{_devices}{$hash_key}{'status'};一样,其实是在打印值。

标签: perl class oop hash


【解决方案1】:

注意   简短的第一部分指的是原始问题,同时发生了变化。


当您设置散列时,您使用$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;
}

还有更简洁、更清晰的方法,但让我们先澄清一下这是否是有意的。


更新 cmets 中的说明

目标是构建一个结构

_device --> id1 --> 状态 --> 0/1 id2 --> 状态 --> 0/1 ...

我们还希望能够读取/更改值,并添加另一种“状态”。让我们首先忘记类并构建这个数据结构。 请参阅教程perlreftut 和数据结构食谱perldsc

在 Perl 中,我们可以为此使用哈希引用,以及进一步嵌套的哈希引用

my $hashref = { 
    'id1' => { 
        'status'  => 0,
        'status2' => 0
    }, 
    'id2' => { 
        'status'  => 0,
        'status2' => 0,
    },
    # ...
};

匿名哈希 { status => 0, status2 => 0 } 被分配为键 'id1', 'id2' 的值。作为对哈希的(无名)引用,它被松散地称为 hashref (就像\%hash 一样)。任何引用都是标量、单个值,因此可以将 hashref 分配给键。这就是我们使用 references 构建嵌套(复杂)数据结构的方式。它们很像指针。

我们可以像这样在代码中填充它

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)。嵌套 hash(ref) 中的键 $stat 也是如此(上面分配了值 0)。我们通过

打印和更改值
$hashref->{$id}{'status'} = 1;

print "$hashref->{$id}{'status'}\n";

我们可以用同样的方式添加另一个“状态”,$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 或使用之前构建的一个。 那么这里有一个方法

sub set_status 
{
    my ($self, $rhstat) = @_;  # check for $rhstat

    foreach my $id (keys %$rhstat) {
        $self->{_devices}{$id} = $rhstat->{$id};
    }
    return 1;
}

如果新的 id 不存在,这将添加它们,或者覆盖现有的值。我们也可以让这个 sub 成为 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 时也会执行相同的操作,以实现接口一致性。

您可以类似地添加“状态”字段,

$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;
}

我们可以使这个方法也有选择地获取和设置新键的值,通过传递 either 一个带有键值对的 hashref(添加键并设置它们), 如上一个arrayref,方法中可以检查什么(见ref)。

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

【讨论】:

  • 也许我完全误解了我的赋值语句在做什么。在您声明我将其分配给不存在的键的地方,我知道我正在分配一组唯一键。对于这些唯一键中的每一个,我想要一个字段“状态”,默认情况下我设置为“0”。请问您将如何进行此分配,以及以后如何通过使用 setter/getter 将“status”的值更改为“1”(如果这真的可行的话)。我还可以问我如何推送一个额外的字段,比如“status2”,并给它一个默认值吗?欣赏它,问候。
  • @Plexus 是的,在我看来,你把它弄反了。 “分配一个键”有点模棱两可——您可以“将(一个值)分配给一个键”,或者“将一个键”“添加一个”到一个散列(带有一些值)。如果你的_ids arrayref 中的值应该成为_devices hashref 中的键,那么你就按照我发布的$self->{_devicess}{$id} = 0 做。然后 hashref _devices 得到一个键 $id ,它的值 0 与之关联。让我们先澄清一下——这是你想要做的吗?
  • @Plexus 但是,如果您希望每个 $id(arrayref _ids 的元素)是一个具有关联标签 'status' 的键,它本身具有一个值,那么您需要为您的 hashref 添加另一个级别,因此 $self->{_devices}{$id}{'status'} = 0。请注意,在编辑之前,$self->{_devices}{ids} = $id_value; 添加了一个键,即字符串 'ids'。 (我认为这不是你想要的。)你现在拥有的,$self->{_devices} = $id_value; 使它变成了其他东西,一个 hashref { '_devices' => $id_value }。查看这些消息并告诉我。
  • @Plexus 我建议好好阅读教程perlreftut 和数据结构食谱perldsc。但是请告诉我,一旦我们弄清楚您需要什么,我会添加到我的答案中。
  • @Plexus 你可能没有意识到的东西。当您不断更改发布的内容时,真的很难回答。任何已经存在的答案都可能无效。最好在您的问题中添加,保留原始语句(尤其是代码)原封不动。
猜你喜欢
  • 2010-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多