【问题标题】:How do I use a Perl package known only in runtime?如何使用仅在运行时已知的 Perl 包?
【发布时间】:2010-10-01 08:37:09
【问题描述】:

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

use $ENV{a};

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

提前致谢, 奥伦

【问题讨论】:

    标签: perl runtime packages require


    【解决方案1】:
    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";

    【讨论】:

    • 这很好,不知道为什么它没有被PCB覆盖?这和评估需求有什么区别吗?还需要手动导入符号吗?
    • 我看到了那句话,内森。但是它在哪里说在我们的情况下 require 更好?你的意思是像“不那么深奥”/规范中的“更好”吗?
    • 这样做的一个问题是,虽然它看起来像“使用”,但实际上只是一个“要求”,似乎没有任何导入发生。
    • @Manni,这就是我的意思。它更规范。
    • 它确实导入了,不幸的是它导入到了 eval 块中。
    【解决方案2】:

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

    my $module = "Foo::Bar";
    eval "require $module";
    

    【讨论】:

      【解决方案3】:

      我会使用UNIVERSAL::require。它同时具有 requireuse 方法来使用一个包。 use 方法也会为包调用 import

      use UNIVERSAL::require;
      $ENV{a}->use or die 'Could not import package:  ' . $@;
      

      【讨论】:

        【解决方案4】:

        如果您不希望在编译时发生这种情况,您可能希望使用require 而不是use,然后手动导入您可能需要的任何符号。请参阅this link to the Perl Cookbook(来自 Google 图书),详细讨论可用于实现所需目标的方法。

        【讨论】:

        • 我们真的应该链接到盗版书籍吗?
        • 更改了指向 Google 图书的链接,我认为他们有权将信息作为“预览版”分发。
        • 谢谢。这感觉好多了。
        【解决方案5】:

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

        也许您需要更改模块的逻辑,但它的工作原理和扩展性非常好(我的应用从四个模块开始,现在有二十个,并且还在增长)。

        【讨论】:

          【解决方案6】:

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

          用你的例子:

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

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

          “加载使您无需知道您是在尝试请求文件还是模块。”

          如果它失败了,它会以类似“Can't locate xxx in @INC (@INC contains: ...”.

          【讨论】:

            【解决方案7】:

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

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

            eval "use $mod_name";

            的较短等价物

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

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

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

            我可能遗漏了一些细节;如果有,请告诉我。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2020-11-02
              • 2013-06-12
              • 1970-01-01
              • 1970-01-01
              • 2018-01-21
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多