Perl:如何使来自需求脚本的变量在需求脚本中可用



示例

out.pl:

(my|our|local|global|whatever???) var = "test";
require("inside.pm");

内部.pm:

print $var;

我不想使用软件包——这让我的需求不堪重负:(谢谢

即使不使用package声明,也总是使用包。默认情况下,您使用的是程序包main

使用our声明的所有变量都是包变量,应该在整个包范围内可用。这里有一个例子:

#! /usr/bin/env perl
# test2.pl
use strict;
use warnings;
our $foo = "bar";
1;

由于$foo被声明为包变量,它将在其他程序中可用:

#! /usr/bin/env perl
use strict;
use warnings;
require "test2.pl";
our $foo;
print "The value of $foo is $foon";

现在我已经给了你足够的绳子,我要告诉你不要用它上吊自杀

这是一个非常非常糟糕的想法。注意到$foo从某种几乎不可能弄清楚的神秘机制中获得了一个值吗?

程序包是否过于复杂?真正地没那么难!看看这个例子:

#! /usr/bin/env perl
# test2.pm
package test2;
use strict;
use warnings;
our $foo = "bar";
1;

除了我添加了package声明,现在调用我的程序test2.pm而不是test2.pl之外,没有什么不同。

以下是我访问它的方式:

#! /usr/bin/env perl
use strict;
use warnings;
use test2;
print "The value of $foo from package test2 is $test2::foon";

我所要做的就是在变量中使用包名称。这是一个坏主意,但它比上面显示的真的,真的坏主意要好得多。

至少,你知道价值的来源。它来自test2.pm。而且,如果在子例程中设置变量,则可以访问该变量。

#! /usr/bin/env perl
# test2.pm
package test2;
use strict;
use warnings;
sub fooloader {
    our $foo = "bar";
}
1;

注意,在子程序fooloader中设置了$foo。这是我的另一个访问程序:

#! /usr/bin/env perl
use strict;
use warnings;
use test2;
&test2::fooloader();
print "The value of $foo from package test2 is $test2::foon";

现在,您可以使用Exporter来导出子例程(甚至变量(,但这不再是您看到的太多了。主要是因为这是一个非常糟糕的想法。没有最初的真的真的很糟糕的想法那么糟糕,但比上面的糟糕想法更糟糕:

#! /usr/bin/env perl
# test2.pm
package test2;
use base qw(Exporter);
our @EXPORT = qw(fooloader);
use strict;
use warnings;
sub fooloader {
    our $foo = "bar";
}
1;

现在,我可以使用子程序fooloader而不使用包名称:

#! /usr/bin/env perl
use strict;
use warnings;
use test2;
fooloader();
print "The value of $foo from package test2 is $test2::foon";

当然,问题是您根本不知道子程序fooloader是从哪里来的。如果使用@EXPORT_OK而不是@EXPORT,则可以使用use test2 qw(fooloader);并记录fooloader函数的来源。它还将帮助您知道不要在自己的程序中创建自己的fooloader函数并覆盖您导入的函数。然后,想知道为什么你的程序不再工作。

顺便说一下,您还可以导出变量,而不仅仅是函数。然而,这变成了一个真的,真的,非常糟糕——没有可怕的想法,因为它首先违反了你使用包的所有原因。如果你打算这么做,为什么还要麻烦包裹呢?为什么不简单地拿起枪朝自己的脚开枪呢?

最好和首选的方法是使用面向对象的Perl,并以THOUGHLY CORRECT way的方式执行。一种让你确切地知道发生了什么以及为什么的方式。并且,可以很容易地弄清楚您的代码在做什么。一种将错误降至最低的方法。

看看完全面向对象的Test2类:

#! /usr/bin/env perl
# Test2.pm
package Test2;
sub new {
    my $class = shift;
    my $self = {};
    bless $self, $class;
    return $self;
}
sub FooValue {
    return "bar";
}
1;

使用Test2类:

#! /usr/bin/env perl
use strict;
use warnings;
use Test2;
my $tester = Test2->new;
print "The value of foo from package test2 is " . $tester->FooValue . "n";

这是最好的方法,因为即使使用包,也可以操纵$test2::foo的值,并且它将在整个程序中更改。想象一下,如果这是$constants::pi,在某个地方你把它从3.14159改成了3。从那时起,使用$constants::pi会给出错误的值。如果使用面向对象的方法,则无法更改方法Constant->Pi的值。它将永远是3.14159。

那么,我们今天学到了什么?

我们了解到,在Perl中,做一些REALLY,REALLY BAD IDEA非常容易,但使用包并不需要那么多工作,所以它只会变成BAD IDEA。而且,如果你开始学习一点面向对象的Perl,你实际上可以毫不费力地用完全正确的方法来完成这一切。

选择权在你。只要记住你射的脚可能是你自己的。

它将与our一起工作。

$ cat out.pl
our $var = "test";
require("inside.pm");
$ cat inside.pm 
print "Testing...n";
print "$varn";
$ perl out.pl
Testing...
test

这是因为our使$var全局化,并且inside.pm在定义了$var的范围内执行。不确定这是推荐的技术,但这仍然是一个有趣的问题!

编辑:需要澄清(好的补丁(基于评论的答案:

来自Perl函数our:的文档

our将一个简单名称与当前包中的包(读:全局(变量相关联,以便在当前词法范围内使用。换句话说,our具有与mystate相同的作用域规则,但不一定要创建变量。

因此,使用our,我们得到了当前包的$var(这里可能是main(,我们可以在其范围内使用它。实际上,它是您需要的文件中的代码的"全局"。

在没有our的情况下引入了真正的全局,因为变量默认为全局。但我不知道有谁会推荐它们。

最新更新