【问题标题】:Non-local return in Perl (return from the caller)Perl 中的非本地返回(从调用者返回)
【发布时间】:2021-02-23 14:48:07
【问题描述】:

有没有办法让我返回 from 我的调用者而不是 to 我的调用者?例如

sub foo {
    bar();
    # this never gets executed
}

sub bar {
    return_from_caller(5);
}

# This prints 5
print foo();

(基本原理:我正在编写一个函数 memoize_self,它从函数本身中记住一个函数。我希望它像这样工作:

sub complex_function {
    my ($x, $y) = @_;
    memoize_self({key => $y, expires_in => '5min'));
    # compute $result
    return $result;
}

memoize_self 将检查其缓存,如果命中,则返回其调用者 的缓存值。否则,它将重新调用函数(使用动态范围的 var 以避免明显的无限循环),将返回值存储在缓存中并再次返回。

如果没有从调用者返回的能力,我可能会使用 $_ 并这样写:

return $_ if memoize_self({key => $y, expires_in => '5min'));

但这是额外的噪音,也没有考虑上下文。)

编辑:对于合理建议 Memoize 的人 - 是的,我应该说,我很了解这个模块。我正在编写一个基于CHI 的更现代、更有特色的 Memoize 版本。

但就这个问题而言,在某些情况下,从函数内部而不是函数外部进行记忆是有用的(Memoize 只做后者)。它可以很容易地自定义缓存键和/或确定是否要为这个特定的调用进行记忆。例如

sub complex_function {
    my $key = ...;   # normalize arguments
    if (...) {       # is it worth memoizing in this case?
        memoize_self({key => $key});
    }
}

我也喜欢它被包裹在函数中的方式,而不是在外面创建自己的行,ala state variables

【问题讨论】:

标签: perl


【解决方案1】:

Continuation::Escape 完全符合您的要求。但是,正如 Nikhil 所指出的,Memoize 是您真正需要的。

【讨论】:

  • 谢谢汉斯! “使用 Scope::Upper qw(展开);”然后 "unwind (5, UP)" 完全符合我在上面示例中的要求。
  • 除了接受@Hans 的回答,你还应该投票。
【解决方案2】:

看看 CPAN 模块 Memoize - 以空间换时间让功能更快,这可能会解决您的问题。

【讨论】:

    【解决方案3】:

    “有没有办法让我从调用者那里返回而不是返回给调用者?”

    是的,有几个。

    • 您可以使用goto 跳转回来。见perldoc -f goto
    • 您可以使用evaldie 进行更多控制跳转。请参阅perldoc -f evalperldoc -f die
    • 您可以goto 它而不是以正常方式调用您的sub。当你这样做时,它将返回到带有goto 调用者的子。见perldoc -f goto

    当然,大多数人会告诉您重写所有内容以避免 goto,并使维护您的代码的人的生活更轻松,但是他们为您做过什么?

    【讨论】:

      【解决方案4】:

      另一种解决方案是使用 Want 模块的 double_return 方法,这会使您的下一个 return 弹出两个调用帧:

      #!/usr/bin/env perl
      use warnings;
      use strict;
      
      use Want;
      
      sub foo {
          Want::double_return;
          return 11;
      }
      sub bar { 
          foo();
          # never executed
          return 55;
      }
      
      # prints 11;
      print bar();
      

      【讨论】:

      • 我没有看到double_return 列在Want 的文档中。它看起来确实是一个内部函数,但缺少文档,不应该依赖它来继续像现在这样工作。
      • 很公平。我不知道为什么我什至记得它。
      猜你喜欢
      • 2013-01-14
      • 1970-01-01
      • 1970-01-01
      • 2012-11-18
      • 1970-01-01
      • 1970-01-01
      • 2013-09-17
      • 1970-01-01
      • 2021-10-28
      相关资源
      最近更新 更多