为什么我不能在Perl的require中使用表达式来构建类名?

Hai*_*ang 0 perl

假设模块AAA::BBB::CCC位于~/modules/AAA/BBB/CCC.pm,并且" ~/modules"处于@INC,那么为什么以下代码不起作用并导致编译错误?

$class = "AAA::BBB" ;
$type = "CCC";
require $class . '::' . $type ;
Run Code Online (Sandbox Code Playgroud)

我尝试使用require AAA::BBB::CCC,它可以工作.如果我确实需要通过将字符串组合在一起来动态地需要模块而不是直接对模块名称进行硬编码,我该怎么办?

谢谢

pil*_*row 7

如果我可以重述你的症状,我认为你的意思是这样失败:

require "AAA::BBB" . "::" . "CCC"; # built from $class and $type;
# => Can't locate AAA::BBB::CCC in @INC (@INC contains ...
Run Code Online (Sandbox Code Playgroud)

因为它找不到一个名为的文件AAA::BBB::CCC.但是,这成功了:

require AAA::BBB::CCC;  # note, this is _not_ quoted
Run Code Online (Sandbox Code Playgroud)

因为perl会搜索部分命名的子目录嵌套模块AAA/BBB/CCC.pm.

这是怎么回事require.从require 的文档EXPR:

如果EXPR是一个单词,则require将采用".pm"扩展名,并在文件名中将"::"替换为"/",以便加载标准模块.

因此,您通常必须将构建的模块名称转换为路径名片段(s!::!/!g附加".pm"),或者将eval构建为您构建的模块名称,正如其他人所建议的那样.


小智 6

我的方法:

my $class = "AAA::BBB";
my $type = "CCC";

my $full_class_name = $class . '::' . $type;
( my $file_name = $full_class_name . '.pm' ) =~ s{::}{/}g;

require $file_name;

$full_class_name->test();
Run Code Online (Sandbox Code Playgroud)

使用eval,如果你只是做"死$ @ if $ @"没有多大意义 - 没有eval就可以正常工作.

制作file_name以及需要$ file_name而不是class的这一额外步骤使得不需要使用基于字符串的eval,这往往相当慢.

当然,如果你想提供某种后备,你仍然可以使用eval:

eval { require $file_name };
if ( my $error = $@ ) {
    ... do something ...
}
Run Code Online (Sandbox Code Playgroud)

但请注意,这是基于块的eval,而不是基于字符串的eval.


And*_*ett 5

来自perldoc -f要求:

但是如果你试试这个:

$class = 'Foo::Bar';
require $class; # $class is not a bareword
#or
require "Foo::Bar"; # not a bareword because of the ""
Run Code Online (Sandbox Code Playgroud)

require函数将查找@INC数组中的"Foo :: Bar"文件,并抱怨在那里找不到"Foo :: Bar".在这种情况下,你可以这样做:

eval "require $class";
Run Code Online (Sandbox Code Playgroud)

因此,您可以尝试这样做:

$class = "AAA::BBB";
$type = "CCC";
eval qq{ require "${class}::${type}" };
Run Code Online (Sandbox Code Playgroud)

  • @depesz没有必要低估这个答案.这就是`require`的文档告诉你如何为`require`提供非赤字参数. (2认同)