16

我有一个 Perl 程序,它需要使用包(我也写)。其中一些包仅在运行时选择(基于某些环境变量)。当然,我不想在我的代码中为所有这些包添加一个“使用”行,但只有一个“使用”行,基于这个变量,比如:

use $ENV{a};

不幸的是,这当然行不通。关于如何做到这一点的任何想法?

在此先感谢,奥伦

4

7 回答 7

9
eval "require $ENV{a}";

" use" 在这里不能很好地工作,因为它只在eval.

正如@Manni 所说,实际上,最好使用require。引自man perlfunc

如果 EXPR 是一个裸字,则 require 假定为“.pm”扩展名,并且
将文件名中的“::”替换为“/”,以便于
加载标准模块。这种形式的模块加载不
冒着改变你的命名空间的风险。

换句话说,如果你试试这个:

        需要 Foo::Bar;# 一个精彩的裸词

require 函数实际上会寻找“Foo/Bar.pm”文件
在@INC 数组中指定的目录中。

但如果你试试这个:

        $class = 'Foo::Bar';
        需要$类;# $class 不是裸词
    #或者
        需要“Foo::Bar”;# 因为“”而不是一个裸词

require 函数将在@INC 中查找“Foo::Bar”文件
数组,并会抱怨在那里找不到“Foo::Bar”。在这个
你可以这样做:

        eval "需要 $class";
于 2009-01-14T12:14:22.507 回答
9

"use" 语句在编译时运行,而不是在运行时。您将需要 require 您的模块:

my $module = "Foo::Bar";
eval "require $module";
于 2009-01-14T12:29:12.537 回答
6

我会使用UNIVERSAL::require。它同时具有使用包的requireuse方法。use方法还将调用包的导入

use UNIVERSAL::require;
$ENV{a}->use or die 'Could not import package:  ' . $@;
于 2009-01-14T14:06:12.310 回答
4

如果您不希望它在编译时发生,您可能想要使用require而不是,然后手动导入您可能需要的任何符号。use请参阅指向 Perl Cookbook(来自 Google 图书)的链接,以很好地讨论可用于实现所需目标的方法。

于 2009-01-14T12:29:04.177 回答
4

我认为在运行时加载的模块可以是插件。我有这种问题,某些情况下的特定模块在运行时作为带有Module::Pluggable的插件加载。

也许您需要更改模块的逻辑,但它可以很好地工作和扩展(我的应用程序从四个模块开始,现在有二十个,并且还在增长)。

于 2009-01-14T16:20:19.543 回答
3

如何使用核心模块Module::Load

用你的例子:

use Module::Load;
load $ENV{a};

“Module::Load - 模块和文件的运行时要求”

“加载消除了了解您是否尝试要求文件或模块的需要。”

如果它失败了,它会以类似"Can't locate xxx in @INC (@INC contains: ..."之类的东西而死。

于 2012-11-05T15:19:22.600 回答
1

许多年后,eval "use $mod_name";似乎工作得很好(至少从 5.8.8 开始)。

优点eval "require $mod_name";是加载模块的默认导出是自动导入的;换句话说:

eval "use $mod_name";

是较短的等价物

eval "require $mod_name"; $mod_name->import();

这是一个测试命令,它通过 env 传递模块的名称。variable mod_name,加载并导入模块,然后使用导入的函数(假设是类似 POSIX 的 shell):

 $ mod_name='Data::Dumper' perl -e 'eval "use $ENV{mod_name}"; print Dumper("hi!")'
 $VAR1 = 'hi!';

我可能遗漏了细微之处;如果是这样,请告诉我。

于 2015-08-18T16:57:15.890 回答