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

use*_*074 2 perl

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

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

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

print $someList;
print $someList2;
Run Code Online (Sandbox Code Playgroud)

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

Dav*_*idO 5

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

首先,在现代版本的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;
}
Run Code Online (Sandbox Code Playgroud)

在此版本中,$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;
    }
}
Run Code Online (Sandbox Code Playgroud)

第二个版本稍微复杂一些,但有两个优点.首先,您只需调用makeSummer例程来制作新的闭包即可开始新的求和.其次,它适用于任何版本的Perl 5,而不仅仅是最近版本足以拥有更新state关键字的版本.

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

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

第四种方法使用包全局变量.我将这个保存为最后一个,因为它最容易被滥用和出错.但是你走了;

our $someAddition = 0;

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

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

sub someRoutine {
    $someAddition += $_ foreach @_;
}
Run Code Online (Sandbox Code Playgroud)

在最后一个版本中,$someAddition是一个全局包,其全局范围使其可以在同一命名空间内的任何子例程的内部和外部使用.


Bor*_*din 5

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

  • 同样重要的是,您use strict每个use warningsPerl 程序的顶部,在变量的第一个使用点上使用. 这项措施将发现许多简单的编码错误,否则您很容易忽视这些错误。my

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

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

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";
Run Code Online (Sandbox Code Playgroud)

输出

300
600
Run Code Online (Sandbox Code Playgroud)

如果您想保护变量不被子例程以外的任何后续代码访问,则只需将它们括在大括号中,如下所示

{
  my $some_addition;

  sub some_routine {
    $some_addition += $_ for @_;
    return $some_addition
  }
}
Run Code Online (Sandbox Code Playgroud)