按顺序遍历哈希成员

时间:2020-02-12 14:15:25

标签: perl oop hash

我如何订购一个类的哈希成员?我的课看起来像这样

    package TestSuiteInterface {

    use Tie::IxHash;

    sub new {
        my ($class, $name) = @_;
        my $self = {};
        my %schedulerdata = {};
        tie(%schedulerdata, 'Tie::IxHash');
        $self->{name} = $name;
        $self->{scheduler} = %schedulerdata;
        bless $self, $class;
        return $self;                                                                                                                                                                                                                        
    }
    sub getVariables {
        my ($self) = shift;
        return $self->{variables}
    }
    sub loadtests {
        my ($self) = shift;
        {
            #tie(my %data, 'Tie::IxHash');                                                                                                                                                                                                   
            #%data = %{$self->{scheduler}};                                                                                                                                                                                                  
            my @scheduler = values %{$self->{scheduler}};
            #die "oops" unless $self->{scheduler}                                                                                                                                                                                            
            $_->() for (@scheduler);
            return 1;
        }
        return 0;
    }
}

以上,我尝试使用Tie :: IxHash。我试图弄清楚如何为$ self-> {scheduler}做到这一点,稍后子类将添加项。例如

package Test {
    use base 'TestSuiteInterface';
    use main_common;
    sub new {
        my ($class, $name) = @_;
        my $self = {};
        class->SUPER::new($name);
        $self->{variables}={};
        $self->{scheduler} = {
            boot_linuxrc => sub{ loadtest("boot/boot_linuxrc"); },
            first_boot => sub{ loadtest("installation/first_boot");}
        };
        bless $self, $class;
        return $self;
    }
}

要使用Tie :: IxHash,我必须在设置变量之前使用它,对吗?因此,最后在负载测试中使用它是没有用的。我可以在构造函数中执行此操作,还是可以在循环内按顺序取回$ self-> {scheduler}?

2 个答案:

答案 0 :(得分:4)

在您的new()方法中,创建一个Tie :: IxHash对象并将其存储在测试对象中。

my %schedulerdata = {};
tie(%schedulerdata, 'Tie::IxHash');
...
$self->{scheduler} = %schedulerdata;

实际上,那里有一些小错误。首先,您使用哈希引用初始化哈希。

my %schedulerdata = {};

真的,您想使用一个空列表对其进行初始化:

my %schedulerdata = ();

或者更好的是,仅依靠Perl将其初始化为空哈希即可。

my %schedulerdata;

然后,您尝试将哈希存储在对象中。但是对象属性只能是标量,因此您需要在对象中存储对哈希的引用。

$self->{scheduler} = \%schedulerdata;

将所有内容放在一起,构造函数方法应如下所示:

sub new {
    my ($class, $name) = @_;
    my $self = {};
    my %schedulerdata;
    tie(%schedulerdata, 'Tie::IxHash');
    $self->{name} = $name;
    $self->{scheduler} = \%schedulerdata;
    bless $self, $class;
    return $self;
}

但是这些问题并不是导致此问题不起作用的原因。稍后,当您为调度程序提供值时。您的代码如下:

$self->{scheduler} = {
    boot_linuxrc => sub{ loadtest("boot/boot_linuxrc"); },
    first_boot   => sub{ loadtest("installation/first_boot"); }
};

但是请考虑这是在做什么。您正在创建一个全新的匿名哈希,并将对该哈希的引用存储在对象中。这将覆盖您精心构造的绑定哈希,然后将其替换为标准(非绑定)哈希。

为了保留哈希的束缚性质,您需要向其添加键/值对-而不是完全覆盖它。我认为这样的代码会起作用。

$self->{scheduler}->{boot_linuxrc} = sub{ loadtest("boot/boot_linuxrc"); };
$self->{scheduler}->{first_boot}   = sub{ loadtest("installation/first_boot"); };

注意:如果您的代码包含use warnings(而Perl代码应始终包含use warnings),则该行:

my %schedulerdata = {};

会触发警告:

参考找到了预期大小均匀的列表

这就是为什么我们总是建议包括use warnings:-)

答案 1 :(得分:1)

最后,我的解决方案是不使用 Tie :: IxHash 。相反,我使用了一个单独的函数来获取有序列表,并将其分配给实例成员。我将以另一种方式发布它,因为@Dave Cross的解决方案仍然是正确的。

sub set_scheduler {    
        my ($self, @list) = @_;
        # get a list of the subroutines of the hash
        my @order    = map { $list[($_ * 2) + 1] } 0 .. (@list / 2) - 1;
        my %schedule = @list;
        $self->{scheduler}       = \%schedule;
        $self->{scheduler_order} = \@order;
        return $self;
    }

@list现在包含4个元素。 [boot_linuxrc,sub {loadtest(“ boot / boot_linuxrc”)},first_boot,sub {loadtest(“ installation / first_boot”)}]。在示例中,set_scheduler使用map使用@list的索引[1]和[3]给我一个子列表。 0 ..(@list / 2)-1 是为了在@order中获得正确的大小(2个项目)。

我将 package Test 中以前的 $ self-> {scheduler} 替换为使用以下项数组的代码波纹管

$self->set_scheduler(
            boot_linuxrc       => sub { loadtest("boot/boot_linuxrc") },
            installer_extended => sub { loadtest("installation/first_boot") }
        );

然后我在loadtests中运行以下内容

$_->() for (@{$self->{scheduler_order}});

感谢@DaveCross

相关问题