【问题标题】:Perl: how to make variables from requiring script available in required scriptPerl:如何使来自需要脚本的变量在需要的脚本中可用
【发布时间】:2011-11-24 10:07:00
【问题描述】:

例子

out.pl:

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

inside.pm:

print $var;

我不想使用包 - 这超出了我的需求 :) 谢谢!

【问题讨论】:

  • 我不认为,您真的想在模块中使用变量,该变量必须由执行脚本指定。如果你把它转过来(在你的脚本中使用模块变量),它甚至不是很漂亮。我强烈建议在函数调用中传递所需的值。或者代替require "inside.pm";,您也可以编写use inside $var 来将任何参数传递给模块。见perldoc use
  • 感谢您的回复。所需的脚本不应被视为一个模块 - 它是包含在主要脚本中的非常小的一段代码,并且可能由其他人以非常有限的方式进行更改。因此,要求来自 OUTER 脚本的变量可用于所需的脚本
  • 您的外部脚本会不仅仅是一个配置文件(即设置一些变量)吗?如果是这样,您可以只使用配置文件而不是可执行脚本...
  • “以受限方式”是什么意思。其他人是否会做出意外或故意破坏脚本的更改。同意@Jan,配置文件可能会更好。
  • 我会以明确的方式说,不受限制

标签: perl variables scope require required


【解决方案1】:

总是使用包,即使您不使用 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 $foo\n";

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

这是一个非常非常糟糕的想法。注意到$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::foo\n";

我所要做的就是在变量中使用包名。这是一个BAD IDEA,但比上面显示的REALLY, REALLY BAD IDEA要好得多。 p>

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

#! /usr/bin/env perl
# test2.pm

package test2;
use strict;
use warnings;

sub fooloader {
    our $foo = "bar";
}
1;

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

#! /usr/bin/env perl
use strict;
use warnings;

use test2;

&test2::fooloader();
print "The value of \$foo from package test2 is $test2::foo\n";

现在,您可以使用 Exporter 来导出您的子例程(甚至是变量),但这已经不是您看到太多的东西了。主要是因为它是一个非常糟糕的想法。不如原来的REALLY REALLY BAD IDEA,但比上面的BAD IDEA还要糟糕:

#! /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::foo\n";

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

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

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

看看彻底面向对象的 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 中很容易做一些非常非常糟糕的想法,但使用包并不需要太多工作,所以它只是一个BAD IDEA。而且,如果您开始学习一点面向对象的 Perl,您实际上可以不费吹灰之力地以完全正确的方式完成所有操作。

选择权在你。请记住,您拍摄的脚可能是您自己的。

【讨论】:

  • +1 用于解释包并显示什么有效/无效,-1 表示“OO 是唯一的真正方式”。您断言调用test2::fooloader 是一个“非常糟糕的主意”,而调用test2->FooValue 是“完全正确的方法”,即使它们之间的唯一区别是使用-> 时附加到参数列表中的额外值的::。 (哦,您既不需要也不(通常)不想在对 subs 的调用前加上 &(“&test2::fooloader();”),即使它们在另一个包中。这是 Perl 4 的保留,副作用不明显在 Perl 5 中。)
  • @DaveSherohman:在我介绍的简单案例中,OO 并没有太大区别。然而,当开发人员说“包太复杂”时,这意味着他们从未超越他们在 Llama 书中学到的东西。我不能责怪他们。大多数 Perl 程序员发现自己被困在小岛上,他们可能是小组中唯一的 Perl 程序员。我想向人们解释 Llama 书以外的东西,并告诉他们看,没那么难。我发现使用 OO 编程技术可以使编程更快,更不容易出错,我想鼓励其他人也学习它。
  • 感谢您的回答,但正如我所说的那样,包的使用超出了我的需求(在这种情况下),而答案对这个问题很重要。
【解决方案2】:

它适用于our

$ cat out.pl
our $var = "test";
require("inside.pm");

$ cat inside.pm 
print "Testing...\n";
print "$var\n";

$ perl out.pl
Testing...
test

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

编辑:需要根据评论澄清(好的补丁)答案:

来自the documentation on the Perl function our

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

所以使用our,我们得到$var和当前包(这里可能是main),我们可以在它的范围内使用它。实际上,它对于您需要的文件中的代码是“全局的”。

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

【讨论】:

  • 不完全。 our 引入了词汇(别名为全局),而不是全局。这意味着our 变量在out.pl 之外不可见。您的示例有效的原因与our 无关。取出our,它仍然可以工作。
  • 评论+1。是的——“全局到所需的代码”是我的想法。它绝对不是一个真正的全局,在没有our 的情况下生成。
猜你喜欢
  • 2015-10-12
  • 1970-01-01
  • 2012-09-13
  • 1970-01-01
  • 2019-03-22
  • 1970-01-01
  • 2013-09-23
  • 1970-01-01
  • 2016-10-16
相关资源
最近更新 更多