如果安装了可选的Perl模块,我如何要求它?

如果安装了可选的Perl模块,我如何要求它?,perl,module,require,Perl,Module,Require,我有Perl代码,它依赖于Term::ReadKey来获取终端宽度。我的安装缺少此模块,因此如果该模块不存在,我希望提供默认设置,而不是引发异常 如何有条件地使用可选模块,而不提前知道它是否可用 # but only if the module is installed and exists use Term::ReadKey; ... 如何实现这一点?查看CPAN模块。它可以满足您的需要。这里有一个基本的解决方案,不需要其他模块: my $rc = eval { require Term

我有Perl代码,它依赖于
Term::ReadKey
来获取终端宽度。我的安装缺少此模块,因此如果该模块不存在,我希望提供默认设置,而不是引发异常

如何有条件地使用可选模块,而不提前知道它是否可用

# but only if the module is installed and exists
use Term::ReadKey;
...

如何实现这一点?

查看CPAN模块。它可以满足您的需要。

这里有一个基本的解决方案,不需要其他模块:

my $rc = eval
{
  require Term::ReadKey;
  Term::ReadKey->import();
  1;
};

if($rc)
{
  # Term::ReadKey loaded and imported successfully
  ...
}
请注意,下面使用
eval{use SomeModule}
的所有答案(我希望它们在下面!:-)都是错误的,因为
use
语句在编译时进行计算,而不管它们出现在代码中的何处。因此,如果
SomeModule
不可用,脚本将在编译后立即失效

(一个
use
语句的字符串eval也会起作用(
eval'use SomeModule';
),但是当
require
/
import
对执行同样的操作时,在运行时解析和编译新代码没有意义,并且在编译时检查语法以引导。)


最后,请注意,为了本例的目的,我在这里使用的
eval{…}
$@
非常简洁。在实际代码中,您应该使用类似或至少类似的方法。

经典答案(至少可以追溯到Perl 4,在“使用”之前很久)是“require()”模块。这是在脚本运行时执行的,而不是在编译时执行的,您可以测试成功或失败,并做出适当的反应。

如果您需要特定版本的模块:

my $GOT_READKEY;
BEGIN {
    eval {
        require Term::ReadKey;
        Term::ReadKey->import();
        $GOT_READKEY = 1 if $Term::ReadKey::VERSION >= 2.30;
    };
}


# elsewhere in the code
if ($GOT_READKEY) {
    # ...
}


注:
1仅在正确加载
require Term::…
时执行。

我认为在使用变量时它不起作用。 请检查说明如何将其与变量一起使用的内容

$class = 'Foo::Bar';
        require $class;       # $class is not a bareword
    #or
        require "Foo::Bar";   # not a bareword because of the ""
require函数将在@INC数组中查找“Foo::Bar”文件,并会抱怨没有在那里找到“Foo::Bar”。在这种情况下,您可以执行以下操作:

 eval "require $class";

这是加载可选模块()的有效习惯用法

这将需要模块(如果可用),并将状态存储在常量中

你可以这样使用它

use constant HAS_READLINE => defined eval { require Term::ReadKey };

my $width = 80;
if ( HAS_READLINE ) {
  $width = # ... code, override default.
}
注意,如果您需要导入它并引入符号,您也可以轻松地进行导入。你可以跟进

use constant HAS_READLINE => defined eval { require Term::ReadKey };
Term::ReadKey->import if HAS_READLINE;
此方法使用常量。这样做的好处是,如果没有此模块,则会从操作树中清除死代码路径

use Module::Load::Conditional qw(check_install);

use if check_install(module => 'Clipboard') != undef, 'Clipboard'; # class methods: paste, copy
使用pragma和核心模块

返回hashref或
undef


pragma文档的一节中也提到了该模块:

Module::Load::Conditional提供了许多函数,您可以使用这些函数查询可用的模块,然后在运行时加载其中一个或多个模块


当然,只有在你也安装了这个的情况下,这才有效。如果你这样做的话,可能是更好的解决方案。是的。。。我不能保证我有那个。虽然Detect::Module是,但它并没有列出它的$installed->modules()返回的模块名列表中的所有模块。哦,我应该先想到这一点+1是的,这确实有效,并且eval块后的分号非常重要。尽可能避免依赖$@。例如,一些模块在加载时可以将$@设置为副作用,而不会实际引发异常。更好的选择是依赖这样一个事实,
eval
在捕获异常时将返回undef,即
if(eval“use Term::ReadKey”){…}
。如果模块(或任何其他内容)在生成异常后执行eval(例如,在SIGDIE处理程序或销毁方法中),$@的值将替换为最新评估的结果。
use Term::ReadKey
eval{require Term::ReadKey}是现在
Term::ReadKey
BEGIN
块中不可用。但在OP的例子中,这不是问题。在我看来,要么标题是错误的,要么所有答案(如果使用check_install()的话,可能除了使用Module::Load::Conditional的答案)都是错误的。标题询问如何检查“在使用前是否有Perl模块”。所有的答案都使用“EVE检测错误,同时要求/加载/使用它”的一些变体。我考虑不同的加载和使用。你可能不同意…Perl关键字有一个非常具体的含义,因此我认为动词“使用”有类似的特定含义。我不确定“加载”指的是什么。。。所以是的,我想我们会同意不同意;-)@EvanCarroll您的答案很好,尽管它在功能上与所选答案相同。但是否有必要改变这个问题?如果我在谷歌上搜索“如何在Perl中在使用模块之前检查模块”,我不太可能搜索“如何在Perl中选择模块”。我认为显示我默认的模块中的内容有助于获得严肃的答案,而不是“为什么?”的评论。@EvanCarroll我理解有时候你会有一个问题,它会作为现有问题的副本关闭。发生的次数比它应该发生的要多。这并不意味着我的问题“不是问题”。你应该与评审员讨论,或者在这里添加你的答案,注意这是一种替代框架。我真希望有一种更简单、噪音更小的方法,使用内置的
use
指令。
use constant HAS_READLINE => defined eval { require Term::ReadKey };

my $width = 80;
if ( HAS_READLINE ) {
  $width = # ... code, override default.
}
use constant HAS_READLINE => defined eval { require Term::ReadKey };
Term::ReadKey->import if HAS_READLINE;
use Module::Load::Conditional qw(check_install);

use if check_install(module => 'Clipboard') != undef, 'Clipboard'; # class methods: paste, copy