帮助在Perl中传递对class子例程的引用

时间:2011-03-09 23:53:50

标签: perl pass-by-reference perl-module

我正在尝试将例程传递给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”中完成了一堆内容并且我需要更多来自该对象的成员。我稍微简化了代码,使其更容易理解。

2 个答案:

答案 0 :(得分:5)

只需制作一个闭包并将其传递给:

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();

}

答案 1 :(得分:2)

$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->()

来调用它