我有依赖于Term::ReadKey
获取终端宽度的 Perl 代码。我的安装缺少这个模块,所以如果模块不存在,我想提供一个默认值而不是抛出异常。
我如何有条件地使用可选模块,而不提前知道它是否可用。
# but only if the module is installed and exists
use Term::ReadKey;
...
我怎样才能做到这一点?
这是一个不需要其他模块的简单解决方案:
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 { ... }
and$@
是为了本示例的目的而简洁。在实际代码中,您应该使用Try::Tiny之类的东西,或者至少要注意它解决的问题。
查看 CPAN 模块Module::Load::Conditional。它会做你想做的事。
经典的答案(至少可以追溯到 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) {
# ...
}
if (eval {require Term::ReadKey;1;} ne 1) {
# if module can't load
} else {
Term::ReadKey->import();
}
或者
if (eval {require Term::ReadKey;1;}) {
#module loaded
Term::ReadKey->import();
}
注意:只有在正确加载的情况下1;
才会执行。require Term::...
use Module::Load::Conditional qw(check_install);
use if check_install(module => 'Clipboard') != undef, 'Clipboard'; # class methods: paste, copy
使用if pragma 和Module::Load::Conditional核心模块。
check_install返回 hashref 或undef
.
该模块也在编译指示文档的另见部分中提到:
Module::Load::Conditional provides a number of functions you can use to query what modules are available, and then load one or more of them at runtime.
这是加载可选模块的有效习惯用法(只要您没有在带有 sigdie 处理程序的代码库中使用它),
use constant HAS_MODULE => defined eval { require Module };
如果可用,这将需要模块,并将状态存储在常量中。
你可以这样使用,
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;
此方法使用常量。这样做的好处是,如果您没有此模块,则会从 optree 中清除死代码路径。
我认为使用变量时它不起作用。请检查这个链接,它解释了它如何与变量一起使用
$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";