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

时间:2009-08-18 12:35:57

标签: perl

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

$class = "AAA::BBB" ;
$type = "CCC";
require $class . '::' . $type ;

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

谢谢

5 个答案:

答案 0 :(得分:7)

如果我可以重述您的症状,我认为您的意思是 失败 ,如下所示:

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

因为找不到名为AAA::BBB::CCC的文件。但是, 成功

require AAA::BBB::CCC;  # note, this is _not_ quoted

因为perl会搜索一个名为AAA/BBB/CCC.pm的子目录嵌套模块。

这就是require的工作原理。来自require EXPR 的文档:

  

如果 EXPR 是一个单词,则require将采用“.pm”扩展名   并使用文件名中的“/”替换“::”   它很容易加载标准模块。

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

答案 1 :(得分: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();

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

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

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

eval { require $file_name };
if ( my $error = $@ ) {
    ... do something ...
}

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

答案 2 :(得分:5)

来自perldoc -f require

  

但如果你试试这个:

$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";

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

$class = "AAA::BBB";
$type = "CCC";
eval qq{ require "${class}::${type}" };

答案 3 :(得分:1)

  

假设模块AAA::BBB::CCC.pm位于~/modules/AAA/BBB/CCC.pm

没有AAA::BBB::CCC.pm之类的东西。只有AAA/BBB/CCC.pmAAA::BBB::CCC

不要混淆包名和模块文件。

答案 4 :(得分:0)

我在当前项目中定义了这个kludgy实用程序类:

package Util::RequireClass;

use strict;
use warnings;

use Exporter 'import'; # gives you Exporter's import() method directly
our @EXPORT_OK = qw(requireClass);

sub requireClass
{
    my $class = shift;
    eval "require $class" or do { die "Ack, can't load $class: $@" };
}

1;