Помогите передать ссылку на подпрограмму класса в Perl

Я пытаюсь передать подпрограмму другой подпрограмме в модуле Perl. Но когда я передаю вспомогательную ссылку, переданная ссылка больше не имеет данных объекта. Может быть, это невозможно сделать таким образом. Строка, о которой у меня есть вопрос, - это строки «если» ниже:

sub get_flag_end {
   my $self = shift;
   return ( -e "$self->{file}" );
}

sub wait_for_end {
   my $self = shift;
   my $timeout = shift;
   my $poll_interval = shift;

   # Is it even possible to pass the oject subroutine and retain the objects data?
   #unless ( $self->timeout( $timeout, $poll_interval, $self->get_flag_end ) ) { # does not work
   unless ( $self->timeout( $timeout, $poll_interval, \&get_flag_end ) ) {       # call happens but members are empty
      die "!!!ERROR!!! Timed out while waiting for wait_for_end: timeout=$timeout, poll_interval=$poll_interval \n";
   }
}

sub timeout {
   my $self = shift;
   my $timeout = shift;
   my $poll_interval = shift;
   my $test_condition = shift;
   until ($test_condition->() || $timeout <= 0) {
      $timeout -= $poll_interval;
      sleep $poll_interval;
   }
   return $timeout > 0; # condition was met before timeout
}

Я знаю, что мог бы изменить подпрограмму "get_flag_end", чтобы она принимала значение в качестве аргумента подпрограммы, но что, если бы в "get_flag_end" была сделана куча вещей, и мне нужно было больше членов от объекта. Я немного упростил код, чтобы за ним было легче следить.


person stephenmm    schedule 09.03.2011    source источник


Ответы (2)


Просто сделайте закрытие и передайте это:

sub wait_for_end {
   my $self = shift;
   my $timeout = shift;
   my $poll_interval = shift;

   my $callback = sub { $self->get_flag_end() };

   unless ( $self->timeout( $timeout, $poll_interval, $callback ) ) {
      die "!!!ERROR!!! Timed out while waiting for wait_for_end: timeout=$timeout, poll_interval=$poll_interval \n";
   }
}

Обновление:

Другой вариант: поскольку timeout является методом того же класса, передать имя метода.

sub wait_for_end {
   my $self = shift;
   my $timeout = shift;
   my $poll_interval = shift;

   my $callback = sub { $self->get_flag_end() };

   unless ( $self->timeout( $timeout, $poll_interval, 'get_flag_end' ) ) {
      die "!!!ERROR!!! Timed out while waiting for wait_for_end: timeout=$timeout, poll_interval=$poll_interval \n";
   }
}

sub timeout {
  my $self = shift;
  my $timeout = shift;
  my $poll_interval = shift;
  my $method = shift;

  # Do whatever

  # Now call your method.
  $self->$method();

}
person daotoad    schedule 10.03.2011
comment
Так что, если бы я хотел узнать больше об этой теме, я мог бы посмотреть документы для закрытия? - person stephenmm; 10.03.2011
comment
@stephenmm, посмотрите perlfaq7 Что за закрытие? perldoc.perl.org/perlfaq7.html#Что-за-закрытие% 3f - person daotoad; 10.03.2011

В вашей строке $test_condition->() вы вызываете подпрограмму, но не передаете ей никаких аргументов. Скорее всего, вы имели в виду $test_condition->($self) или, возможно, как $self->$test_condition

Вот рефакторинг вашего кода, исправляющий несколько других проблем:

sub get_flag_end {
   my $self = shift;
   return -e $self->{file}; # no need to quote the variable
}

sub wait_for_end {
   my ($self, $timeout, $poll_interval) = @_;  # unpack many args at once

   unless ( $self->timeout( $timeout, $poll_interval, $self->can('get_flag_end') ) ) {
      die "!!!ERROR!!! Timed out while waiting for wait_for_end: timeout=$timeout, poll_interval=$poll_interval \n";
   }
}

sub timeout {
   my ($self, $timeout, $poll_interval, $test_condition) = @_;
   until ($self->$test_condition || $timeout <= 0) {
      $timeout -= $poll_interval;
      sleep $poll_interval;
   }
   return $timeout > 0; # condition was met before timeout
}

В зависимости от остальной части вашей реализации, создание подпрограммы, которая знает свой вызывающий код, может быть лучше. Вы можете сделать это в Perl с помощью замыкания:

unless ( $self->timeout( $timeout, $poll_interval, sub {$self->get_flag_end} )){

Здесь создается новая подпрограмма, которая запоминает значение $self. Вы бы назвали это без аргументов $test_condition->()

person Eric Strom    schedule 09.03.2011