Помощ при преминаване на препратка към подпрограма на клас в Perl

Опитвам се да предам рутина към друга подпрограма в Perl модул. Но когато предам подреференцията, предадената в ref вече няма обектни данни. Може би не е възможно да го направите по този начин. Редът, за който имам въпрос, е редовете „освен ако“ по-долу:

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#What's-a-closure% 3е - 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