L oop через га sh член в заказе - PullRequest
0 голосов
/ 12 февраля 2020

как я могу заказать ха sh члена класса? Мой класс выглядит так:

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

Выше я пытаюсь использовать T ie :: IxHa sh. я пытаюсь выяснить, как я мог бы сделать это для $ 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;
    }
}

Чтобы использовать T ie :: IxHa sh, я должен использовать его до того, как переменная будет установлена, верно? Поэтому использовать его в нагрузочных тестах в конце не полезно. Могу ли я сделать это в конструкторе или как еще я могу вернуть $ self -> {scheduler} в порядке внутри al oop?

Ответы [ 2 ]

4 голосов
/ 12 февраля 2020

В вашем методе new() вы создаете объект T ie :: IxHa sh и сохраняете его внутри тестового объекта.

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

На самом деле, есть пара небольших ошибок там. Во-первых, вы инициализируете свой ha sh ссылкой h sh.

my %schedulerdata = {};

Действительно, вы хотите инициализировать его пустым списком:

my %schedulerdata = ();

Или лучше просто положитесь на Perl, чтобы инициализировать его как пустой ха sh.

my %schedulerdata;

И, во-вторых, вы пытаетесь сохранить ха sh в своем объекте. Но атрибуты объекта могут быть только скалярами, поэтому вам нужно сохранить ссылку на ha sh в вашем объекте.

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

Но подумайте, что это делает. Вы создаете совершенно новый анонимный ха sh и сохраняете ссылку на этот ха sh в своем объекте. Это перезапишет ваш тщательно построенный привязанный ха sh и заменит его стандартным (не привязанным) ха sh.

Чтобы сохранить привязанный характер вашего ха sh, вам необходимо добавьте пары ключ / значение к нему - не перезаписывайте его полностью. Я думаю, что такой код будет работать.

$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 голос
/ 13 февраля 2020

Мое решение, в конце концов, было go без T ie :: IxHa sh. Вместо этого я использовал отдельную функцию, чтобы получить упорядоченный список и назначить его членам экземпляра. Я опубликую это как-то иначе, так как решение от @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_linuxr c, sub {loadtest ("boot / boot_linuxr c")}, first_boot, sub {loadtest ("installation / first_boot")}]. Set_scheduler использует map, чтобы дать мне список подпрограмм, используя индексы [1] и [3] @list в примере. 0 .. (@list / 2) - 1 должен получить только правильный размер (2 элемента) в порядке @.

Я заменяю предыдущий $ self-> {scheduler} в пакете Test с кодом ниже, который использует массив элементов

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

Затем я запускаю следующее в loadtest

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

Спасибо @ DaveCross

...