【问题标题】:How to check if perl module is available?如何检查 perl 模块是否可用?
【发布时间】:2021-04-16 12:59:27
【问题描述】:

我找到了this:

my $rc = eval
{
  require Term::ReadKey;
  Term::ReadKey->import();
  1;
};

if($rc)
{
  # Term::ReadKey loaded and imported successfully
  ...
}

但这不适用于在其他模块中定义的包,例如:

{
  package Hi::Test;
}    

my $rc =  eval{ require Hi::Test };

$rc 在这里是假的。

如何检查“Hi::Test”是否可用?

【问题讨论】:

标签: perl module namespaces package


【解决方案1】:

我假设该包中确实发生了一些事情,而不仅仅是一个空块。

以下代码检查该包的符号表中是否有任何条目。它很脏,但只要注册了 subs 或 package 变量,它就可以工作。

{
  package Hi::Test;

  sub foo;
}

my $rc =  eval{ require Hi::Test };
if (! $rc) {
  $rc = do {
    no strict;
    *stash = *{"Hi::Test::"};
    scalar keys %stash;
  }
}

print $rc;

它将打印1

【讨论】:

  • defined(*{"Hi::Test::"}) 就足够了。
【解决方案2】:

你想要defined(*Hi::Test::) 之类的东西,只是简单地提及*Hi::Test:: 会创建包。

$ perl -E'
   say defined(*Hi::Test::) ? "exists" : "doesn'\''t exist";
'
exists

通过使用符号引用,您可以避免这个问题。

$ perl -E'
   { package Hi::Test }
   say defined(*{"Hi::Test::"}) ? "exists" : "doesn'\''t exist";
   say defined(*{"Hi::TEST::"}) ? "exists" : "doesn'\''t exist";
'
exists
doesn't exist

将该代码放在子程序中以使事情更清洁。

$ perl -E'
   use strict;
   use warnings;

   sub test_for_package {
      my ($pkg_name) = @_;
      $pkg_name .= "::";
      return defined(*$pkg_name);
   }

   { package Hi::Test }
   say test_for_package("Hi::Test") ? "exists" : "doesn'\''t exist";
   say test_for_package("Hi::TEST") ? "exists" : "doesn'\''t exist";
'
exists
doesn't exist

请注意,创建包Foo::Bar::Baz 也会创建包FooFoo::Bar

【讨论】:

  • eval 'require Some::Pkg' 破坏全局命名空间时,perl 中似乎存在一个错误。 rt.perl.org/Ticket/Display.html?id=126077
  • @Eugen Konkov,是的,如前所述,引用 Some::Pkg 会创建包,因此 require Some::Pkg 会创建包,即使它最终会引发异常。
  • @Eugen Konkov,很有趣。 no strict qw( refs ); 确实不是必需的。固定。
  • 我认为这是由于'已定义'不会产生错误
  • 看起来确实如此。当您意识到 defined 仅在严格错误被抛出后才被调用时,这将是非常有趣的。这意味着他们通过在编译器中对其进行特殊处理来竭尽全力支持这一点。
【解决方案3】:

我对此有点生疏,但我认为你的 require 无论如何都会失败 - 这个错误:

#!/usr/bin/perl

{
    package Hi::Test;

    sub foo {
        print "bar\n";
    }
}

{
    package main;
    require Hi::Test; 
}

这个错误 - 它无法找到它 @INC(因为它不在 @INC 中)。 userequire 都专门告诉 perl“出去找一个模块文件”

但你仍然可以调用 'foo':

Hi::Test::foo();

因此您无法使用 eval 测试模块的加载,也无法检查 %INC

但是你可以做的是检查%Hi:::

use Data::Dumper;
print Dumper \%Hi::;
print Dumper \%Hi::Test::;

这给了我们:

$VAR1 = {
          'Test::' => *{'Hi::Test::'}
        };
$VAR1 = {
          'foo' => *Hi::Test::foo
        };

所以我们可以:

print "Is loaded" if defined $Hi::{'Test::'}

【讨论】:

    【解决方案4】:

    更新
    我找到了这个线索:

    my $module =  *main::;
    my @sub_name =  split '::', $full_name;
    while( each @sub_name ) {
        $module =  $$module{ $sub_name[$_].'::' };
    }
    print "Module is available"   if $module;
    

    this 答案相比,它不会在全局存储中创建额外的变量

    【讨论】:

    • 请注明您在哪里找到的。
    • 这可以在perlmod 中找到——每个包都有一个名为%packagename:: 的魔法哈希,所以你可以这样做print Dumper \%main::——或者在这个例子中:print Dumper \$main::{'Hi::'};$VAR1 = \*{'::Hi::'};。你不能做的是:print Dumper \$main::{'Hi::Test::'};
    • %::%main::%main::main::%main::main::main:: 都是同一个命名空间。我会从您的代码中删除main
    猜你喜欢
    • 2010-10-22
    • 2012-03-09
    • 1970-01-01
    • 2021-01-04
    • 2016-04-13
    • 1970-01-01
    • 2022-06-20
    • 1970-01-01
    • 2020-04-03
    相关资源
    最近更新 更多