题
我有以下Perl代码,它依赖于 Term :: ReadKey
来获取终端宽度;我的NetBSD版本缺少此模块,因此我希望在模块丢失时将终端的宽度默认为80.
我无法弄清楚如何有条件地使用模块,提前知道它是否可用。我当前的实现只是退出一条消息,说如果它不存在就找不到 Term :: ReadKey
。
#/usr/pkg/bin/perl -w
# Try loading Term::ReadKey
use Term::ReadKey;
my ($wchar, $hchar, $wpixels, $hpixels) = GetTerminalSize();
my @p=(2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97);
my $plen=$#p+1;
printf("num |".("%".int(($wchar-5)/$plen)."d") x $plen."\n",@p);
我在NetBSD上使用Perl 5.8.7,在CygWin上使用5.8.8 你能帮我更有效地将它实现到我的脚本中吗?
解决方案
这是一个不需要其他模块的简单解决方案:
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'使用SomeModule';
),但是在运行时解析和编译新代码是没有意义的。 require
/ import
对执行相同的操作,并在编译时进行语法检查以进行引导。)
最后,请注意我在这里使用 eval {...}
和 $ @
是简洁的。在实际代码中,您应该使用 Try :: Tiny 之类的内容,或者至少< a href =“http://search.cpan.org/dist/Try-Tiny/lib/Try/Tiny.pm#BACKGROUND”rel =“noreferrer”>了解它所解决的问题。
其他提示
查看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;
仅在要求正确加载Term :: ...
时执行。
我认为使用变量时它不起作用。 请查看此链接,其中说明了如何将其与变量一起使用
$class = 'Foo::Bar';
require $class; # $class is not a bareword
#or
require "Foo::Bar"; # not a bareword because of the ""
require函数将查找“Foo :: Bar”。文件在@INC数组中并且会抱怨没有找到“Foo :: Bar”那里。在这种情况下,你可以这样做:
eval "require $class";