无法在运行时加载“Cwd”(以及其他非核心模块)
Posted
技术标签:
【中文标题】无法在运行时加载“Cwd”(以及其他非核心模块)【英文标题】:Cannot load `Cwd` (and other, non-core, modules) at runtime 【发布时间】:2017-04-26 23:02:35 【问题描述】:假设我想在运行时加载一个模块。我希望这可以工作
use warnings;
use strict;
eval
require Cwd;
Cwd->import;
;
if ($@) die "Can't load Cwd: $@"
say "Dir: ", getcwd;
但不是,根据Bareword "getcwd" not allowed ...
。
Cwd 默认导出getcwd
。我尝试将函数名称赋予import
,并尝试使用它的其他函数。
它使用全名say Cwd::getcwd
,所以我认为它没有导入。
这与我尝试过的其他几个核心模块的尝试一样,例如
use warnings;
use strict;
eval
require List::Util;
List::Util->import('max');
;
if ($@) die "Can't load List::Util: $@"
my $max = max (1, 14, 3, 26, 2);
print "Max is $max\n";
添加了注意事项 显然,带括号的函数调用为编译器提供了线索。但是,在我看来,问题仍然存在,请参阅最后的 EDIT。此外,上面模块中的first BLOCK LIST
之类的函数也不起作用。
但是,它不适用于我尝试过的一些(成熟的)非核心模块。更糟糕,更令人困惑的是,即使使用完全限定的名称,它也不起作用。
如果在运行时使用require
,我可以想象在编译时使用的符号(函数)是未知的,但它适用于(其他)核心模块。我认为这是在运行时加载的标准方式。
如果我需要在动态加载时使用全名,那很好,但是不一致是怎么回事?以及我如何做在运行时加载(和使用)非核心模块?
我也尝试了Module::Load::Conditional
,但没有成功。
我缺少什么,如何在运行时加载模块? (尝试使用5.16
和5.10.1
。)
编辑
如Matt Jacob 所述,带括号的调用有效,getcwd()
。但是,鉴于perlsub
NAME LIST;
# 如果预先声明/导入,括号是可选的。
这意味着导入不起作用,为什么仍然存在问题。
此外,必须根据模块的加载方式使用不同的语法是不好的。此外,我无法让非核心模块以这种方式工作,尤其是那些语法像 List::MoreUtils 的模块。
【问题讨论】:
Perl 不知道它是一个子程序。你需要:&getcwd
(不太好)、use subs qw(getcwd);
(更好),或者只是getcwd()
(最好)。
@MattJacob 谢谢,确实有效。但是,问题仍然存在,正如我在最后添加的注释中所解释的那样。
在编译 getcwd 调用时导入还没有工作,所以你得到了严格的错误(或者没有严格,把它解释为字符串"getcwd"
)。添加括号告诉 perl 这是一个子调用,而不是一个简单的单词。
@ysth 好的,谢谢,我想到了(我可以想象...)——但它确实适用于其他核心模块,即使涉及语法.比如说,在List::Util
我可以使用max BLOCK LIST
。可以说这可能是因为的语法(给编译器或类似的提示)......但它不应该依赖于此。那么如何动态加载呢?我认为这是常态。
重点是在编译过程之后导入模块。更改后 eval 需要 Cwd; cwd->导入; ;进入 Beginn-Block BEGIN 需要 Cwd; cwd->导入; ;一切正常。
【参考方案1】:
首先,这与核心与非核心模块无关。当解析器必须猜测特定标记是否是函数调用时,就会发生这种情况。
eval
require Cwd;
Cwd->import;
;
if ($@) die "Can't load Cwd: $@"
say "Dir: ", getcwd;
在编译时,main::
符号表中没有 getcwd
。没有任何提示表明它是一个函数(getcwd()
或 &getcwd
),解析器无法知道,strict
抱怨。
eval
require List::Util;
List::Util->import('max');
;
if ($@) die "Can't load List::Util: $@"
my $max = max (1, 14, 3, 26, 2);
在编译时,main::
符号表中没有 max
。但是,由于您使用括号调用max
,因此解析器可以猜测它是稍后定义的函数,因此strict
不会抱怨。
在这两种情况下,strict
检查都发生在 import
被调用之前。
List::MoreUtils 很特别,因为函数使用原型。如果函数定义在编译时不可见,则忽略原型。因此,您不仅需要向解析器提示您正在调用一个函数,而且还必须以不同的方式调用它,因为原型将被忽略:
use strict;
use warnings 'all';
use 5.010;
eval
require List::MoreUtils;
List::MoreUtils->import('any')
;
die "Can't load List::MoreUtils: $@" if $@;
say 'found' if any( sub $_ > 5 , 1..9 );
【讨论】:
非常感谢。因此,在运行时加载时,必须考虑编译器并使用不同的语法。很高兴知道。 (我已经看过很多次了,但从来没有看到过这种暗示。) 我认为符号不为人所知,如问题中所述,但后来我认为它对其他模块“有效”让我相信正在做一些魔法(对于核心模块,我想)。 即使在其他情况下,您也必须考虑解析器,例如sub foo ... foo;
可以,但foo; sub foo ...
不行。所以有些人总是用括号;太容易被咬了。这只是您应该避免使用原型的另一个例子。
是的,原型让我对整个事情感到厌烦。我从不靠近他们(也不认识他们),所以我没有意识到这个模块使用了它。 (显然,我需要更仔细地重新阅读 Perl 文档,并确保始终查看我使用的模块的源代码。)谢谢。以上是关于无法在运行时加载“Cwd”(以及其他非核心模块)的主要内容,如果未能解决你的问题,请参考以下文章