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

发布于 2024-10-21 01:05:35 字数 1143 浏览 5 评论 0原文

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

I am trying to pass a routine to another subroutine within a Perl module. But when I pass the sub reference the passed in ref no longer has the object data. Maybe its not possible to do it this way. The line I have a question about is the "unless" lines below:

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
}

I know that I could change the "get_flag_end" routine to take the value as an argument to the subroutine but what if there was a bunch of stuff done in "get_flag_end" and I needed more members from the object. I simplified the code a bit to make it a little easier to follow.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

零時差 2024-10-28 01:05:35

只需创建一个闭包并将其传入:

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

Update:

另一个选项是,由于 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();

}

Just make a closure and pass that in:

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

Update:

The other option is, since timeout is a method of the same class, pass in a method name.

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

}
我喜欢麦丽素 2024-10-28 01:05:35

在您的 $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->()

In your $test_condition->() line, you are calling the subroutine but not passing it any arguments. Chances are what you meant was $test_condition->($self) or perhaps as $self->$test_condition

Here is a refactor of your code, correcting a few other issues:

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
}

Depending on the rest of your implementation, creating a subroutine that knows its invocant might be better. You can do this in Perl with a closure:

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

Here a new subroutine is created, which remembers the value of $self. You would call it without arguments $test_condition->()

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文