【问题标题】:Storing the return value from a perl subroutine "as is"“按原样”存储 perl 子例程的返回值
【发布时间】:2015-03-12 02:29:54
【问题描述】:

我需要包装一个子程序,以便它可以在返回其原始返回值之前触发之前/之后的事件。一切正常,除非 coderef 返回一个数组,它将被强制转换为 arrayref。有时我确实想要一个数组引用,所以我不能只检查引用类型并重铸为数组。我也尝试过使用wantarray,它仍然返回一个arrayref。

我目前正在尝试这样做

$owner->methods->each(sub { # Methods is a hash container where each entry is a mapping of a method name to its implementation (as a coderef)
    my ($key, $val) = @_;

    return if $key eq 'trigger' || $key eq 'triggerBefore' || $key eq 'before' || $key eq 'on'; # Ignore decorating keys that would cause infinite callbacks
    $owner->methods->set($key, sub { # Replace the original sub with a version that calls before and after events
      my ($obj, @args) = @_;

      $owner->triggerBefore($key, @args);
      my $return = $val->(@args); # Return could be anything...
      $owner->trigger($key, $return);
      return $return;
    });
  });

我也尝试用以下内容替换退货,但无济于事:

return (wantarray && ref $return eq 'ARRAY') ? @$return : $return;

如果我不存储返回值而是return $val->(@args);(但随后我失去了“之后”触发器),一切正常。有没有办法“按原样”存储返回值而不是将其存储在标量中?

【问题讨论】:

  • Contextual::Return 可能值得一看

标签: perl


【解决方案1】:

如果我理解正确,您的原始子例程在列表上下文中调用时返回一个数组,在标量上下文中调用时返回一个数组引用。

您需要在调用者提供的相同调用上下文中调用被包装的 sub,并存储并稍后在适当的时候返回其返回值。这具有额外的优势,例如,在 void 上下文中调用时,可以让上下文感知子跳过冗长的计算。

这使包装有点复杂。您可能还想传入@_,以防子也在那里进行任何修改:

sub {
  ...
  my $wa = wantarray;
  my @ret;

  ... trigger_before() ...

  unless (defined($wa)) {           # void
    $original_sub->(@_);
  } elsif (not $wa) {               # scalar
    $ret[0] = $original_sub->(@_);
  } else {                          # list
    @ret = $original_sub->(@_);
  }

  ... trigger_after() ...

  return unless defined($wa);
  return $wa ? @ret : $ret[0];
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-07-04
    • 1970-01-01
    • 1970-01-01
    • 2015-01-19
    • 2014-07-02
    • 1970-01-01
    • 1970-01-01
    • 2013-08-14
    相关资源
    最近更新 更多