在 perl 中的多个子例程调用中保留变量的值

Preserve a variable's value across multiple subroutine calls in perl

只是想知道在对同一子程序的多次调用中保留变量值的最佳方法是什么。即

$someList  = &someRoutine(100, 200);
$someList2 = &someRoutine(100, 200);

sub someRoutine {
    $someAddition = 0;
    foreach $someSum (@_){
        $someAddition += $someSum;
    }
    return $someAddition
}

print $someList;
print $someList2;

基本上,someList 应该打印 300 而 someList2 应该打印 600。我如何才能使 someList2 打印 600?我希望在多个子例程调用中保留 $someAddition。

有几种方法可以做到这一点。我将演示其中的两个:

首先,在现代版本的 Perl 中,您可以使用 state:

use feature qw/state/; 

print someRoutine(100,200), "\n";
print someRoutine(100,200), "\n";

sub someRoutine {
    state $someAddition = 0;
    foreach my $someSum ( @_ ) {
        $someAddition += $someSum;
    }
    return $someAddition;
}

在这个版本中,$someAddition 变量将被初始化为零一次,而且只有一次。从那时起,该值将在调用之间保留。

另一个版本正在使用词法闭包。这是一个例子:

my $summer = makeSummer();
print $summer->(100,200), "\n";
print $summer->(100,200), "\n";

sub makeSummer {
    my $someAddition = 0;
    return sub {
        $someAddition += $_ foreach @_;
        return $someAddition;
    }
}

第二个版本稍微复杂一些,但有两个优点。首先,您可以简单地通过调用 makeSummer 例程来创建新的闭包来开始新的求和。其次,它可以在任何版本的 Perl 5 上运行,而不仅仅是最新的版本可以使用更新的 state 关键字。

如果您不关心在声明 sub 之前初始化有状态变量,您也可以这样做:

my $someAddition;
sub someRoutine {
    $someAddition = 0 unless defined $someAddition;
    foreach my $someSum( @_ ) {
        $someAddition += $someSum;
    }
    return $someAddition;
}

第四种方法是使用包全局变量。我把这个留到最后,因为它最容易被滥用和犯错。但是给你;

our $someAddition = 0;

someRoutine(100,200);
print "$someAddition\n";

someRoutine(100,200);
print "$someAddition\n";

sub someRoutine {
    $someAddition += $_ foreach @_;
}

在最后一个版本中,$someAddition 是一个全局包,其全局作用域使其在同一命名空间内的任何子例程内外都可用。

看看 "man perlsub" 中的 Persistent Private Variables

  • 我假设您至少在使用 Perl 5 的变体?自 22 年前的第一个 Perl 5 版本以来,在子例程调用中使用和号 & 一直是不好的做法。

  • 同样重要的是,你 use strictuse warnings 每个 Perl 程序的顶部,并声明你的变量 ay他们的第一个使用点是 my。这是一种可以发现许多您很容易忽略的简单编码错误的方法。

  • Perl 变量名只能使用小写字母、数字和下划线。大写字母保留用于全局标识符,例如包名称。

到目前为止,创建 static 变量的最简单和最常用的方法就是在子例程之外声明它。像这样

use strict;
use warnings;

my $some_list  = some_routine(100, 200);
my $some_list2 = some_routine(100, 200);

my $some_addition;

sub some_routine {
  $some_addition += $_ for @_;
  return $some_addition
}

print $some_list, "\n";
print $some_list2, "\n";

输出

300
600

如果你想保护变量不被子程序以外的任何后续代码访问,那么只需将它们括在大括号中,就像这样

{
  my $some_addition;

  sub some_routine {
    $some_addition += $_ for @_;
    return $some_addition
  }
}