如何在perl中创建静态变量,以便可以从另一个脚本中访问

ih99xse1  于 2022-11-15  发布在  Perl
关注(0)|答案(2)|浏览(141)

我有一个脚本(A.pl)和一个包(B.pm),我想在B.pm中创建一个静态变量,以便A.pl可以访问它。
第1001章:我的A.pl

use lib 'path/to/B_Package';

for loop 10 times {
  fun(age);
}
if ($count>0) {
  print "script fails";
}

第1001章:我的B.pm

package B {
  fun() {
    my $age_given = shift;
    my $count;

    eval {
      result = someFileHandling;
    } or die {
      $count++; 
    }
  }
}
dwthyt8l

dwthyt8l1#

我会质疑这样的设计,下面提供了一些替代方案。
但是,是的,这是可以做到的--声明为our的变量可以通过其完全限定名来访问。
在程序包文件Pack.pm

package Pack;    
use warnings;
use strict;

use Exporter qw(import);
our @EXPORT_OK = qw(func);

our $count = 7;

sub func { ++$count }

1;

以及其用户

use warnings;
use strict;
use feature 'say';

use Pack qw(func);

for (1..2) {
    func();
    say "Current value of a global in 'Pack': ", $Pack::count;
}

$Pack::count = 123;
say "Current value of a global in 'Pack': ", $Pack::count;

因此在Pack::func()中对$count所做的修改可以在调用程序中看到。更重要的是,$Pack::count可以由解释器中的任何代码直接编写。
像上面提到的$count这样的包全局变量是一种很难被合理使用的棘手的东西,但很容易被滥用。
一般情况下,您不需要它们:它们的使用与将软件划分为通过明确定义的接口进行通信的组件的关键思想相反,它们引入了不受控制的耦合,从而破坏了作用域等。使用这些变量时,代码中不同的组件会纠缠在一起。
但是它们当然是有用的,并且 * 被 * 用于库中,主要用于常量和参数。
现在,让他们也改变?这可能会失去控制,即使这也在库中使用(通过设置参数来控制他们的行为),它更接近于“上帝级”的模拟,一个所有控制的实体。在这一点上,我会直截了当地称之为有缺陷的和麻烦制造者。
为什么不让subs处理计数和 * 返回 * 更新的值呢?例如,他们可以使用state pragma来保存值,甚至使用文件作用域变量,只要这是内部事务,不允许外人干预。
以下是修订版Pack.pm中提到的两种方法的示例

package Pack;    
use warnings;
use strict;
use feature qw(state);

use Exporter qw(import);
our @EXPORT_OK = qw(count func1 func2);

my $count = 7;

sub func1 { ++$count }  # sets counter while doing its other work

sub count {                   # add check that input is numeric
    $count += shift  for @_;  # Set count if values passed,
    return $count;            # return value in either case
}

sub func2 {                       
    state $count = 0;             # keeps count (its own $count)
    return $count += shift // 1;  # demo: add some and return
}

1;

演示其用途:

use warnings;
use strict;
use feature 'say'; 

use Pack qw(count func1 func2);

say "Call func2(), using 'state' feature, with its own counter: ";
for (1..2) { say "func2($_): ", func2($_) }
say '';

say "Set value for a file-wide counter, retrieve using count(): ";
for (1..2) { func1() }    
say "Count is: ", count();

say "Use count() to set values as well: ";
for (1..2) {  say "For #$_: ", count($_) }

此打印

Call func2(), using 'state' feature, with its own counter: 
func2(1): 1
func2(2): 3

Set value for a file-wide counter, retrieve using count(): 
Count is: 9
Use count() to set values as well: 
With 1: 10
With 2: 12

下一步是将其作为一个类,然后您可以用非常自然的方式实现任何类型的计数器。
有关变量的更多信息,请参阅this postthis post以及Effective Perler article
†一个our变量严格地说 * 不是 * 一个全局变量,而是一个词法变量,它的别名是一个同名的包变量(一个“真正的”全局变量)。

g6baxovj

g6baxovj2#

我认为有一个更好的方法来做我猜你想做的事情。我认为你想尝试一些事情一定的次数,如果你不能达到这个目标就给予。
当你调用你的子程序时,你想让它知道要尝试多少次。同时,你想知道它什么时候失败。
你不需要为此共享变量,die会帮你处理这个问题,你可以任意多次调用这个函数,每次你没有从eval中得到一个值,就把它当作一个错误:

my $errors = 0;
foreach ( 1 .. 10 ) {
    my $result = eval { do_this($age) };
    $errors++ unless defined $result;
    }
    
print "Script fails" if $errors > 0;

在子程序中,你不需要担心已经执行了多少次,因为这是在更高的层次上进行的。你可以查看子例程的结果来判断它是否失败,并在更高的层次上调整计数器。现在子例程可以专注于它的一小部分,而不是考虑你为什么调用它。你也不需要在这个级别上不需要eval,因为在更高级别上已经有了它。

sub do_this {
    my( $age ) = @_;
    ... some file handling ...
    }

工厂

但是让我们假设有一些好的理由让一个较低的子例程知道它的计数。我不想污染每个人的子例程-假设程序中的其他10个地方也调用了这个子例程,并且它们都失败了。这应该算作你的调用吗?你可能不希望这样。但是,有一种方法可以解决这个问题。当你需要的时候,你可以创建一个新版本的子例程。一个 factory 是一个可以生成其他子例程的子例程。
假设你想尝试某件事一定次数,但你可能也想做多次。每次你想尝试时,都创建一个新的子例程。告诉该子例程它可以尝试多少次:

sub some_factory {
    my( $max_tries ) = @_;
    
    sub anon_thingy {
        my( $age ) = @_;
        for ( 1 .. $max_tries ) {
            ... file handling ... or die ...
            }
        }
    }

您的程序将类似于:

my $try_this = some_factory( 10 );

my $result = eval { $try_this->($age) };
print "Script fails" unless defined $result;

在同一个程序中,你可以重复这样做,每个生成的代码引用都跟踪它自己的使用,而不会打扰其他子程序:

foreach $age ( list_of_ages() ) {
    my $new_sub = some_factory( 10 );
    my $result = eval { $new_sub->($age) };
    print "Script fails" unless defined $result;
    }

我在Intermediate PerlMastering Perl中花了相当多的时间在这类东西上。

相关问题