【问题标题】:Perl - eval not trapping "use" statementPerl - eval 不捕获“使用”语句
【发布时间】:2012-06-16 18:24:14
【问题描述】:

我想检测用户何时缺少所需的模块并打印友好的错误消息,说明他们需要安装什么。

到目前为止,我尝试将其放在脚本的开头:

eval {
    use IO::Uncompress::Gunzip qw(gunzip $GunzipError) ;
};
if ($@) {
    die "Error: IO::Uncompress::Gunzip not installed: $@";
}

但 Perl 似乎死在“使用”行而不是“死”行,并且从不打印我的错误消息。

【问题讨论】:

标签: perl


【解决方案1】:
use IO::Uncompress::Gunzip qw( gunzip $GunzipError );

简称

BEGIN {
   require IO::Uncompress::Gunzip;
   import IO::Uncompress::Gunzip qw( gunzip $GunzipError );
}

BEGIN 块在编译后立即进行评估。这意味着您的代码可以:

  1. 编译阶段:
    1. 编译eval 语句。
      1. 已编译 BEGIN 块。
        1. 编译require IO::Uncompress::Gunzip;
        2. 编译import IO::Uncompress::Gunzip qw( gunzip $GunzipError );
      2. 评估BEGIN 块。
        1. 评估require IO::Uncompress::Gunzip;
        2. 评估import IO::Uncompress::Gunzip qw( gunzip $GunzipError );
    2. 编译if语句。
  2. 运行阶段:
    1. 评估(空)eval 语句。
    2. 评估if 语句。

如果在步骤 1.1.2.1 中发生异常,则在步骤 2.1 中运行的 eval 将无法捕获它!


解决方案:

你从与

等价的东西开始
BEGIN {
   require IO::Uncompress::Gunzip;
   import IO::Uncompress::Gunzip qw( gunzip $GunzipError );
}

您想捕获来自require 的错误,因此只需在require 周围添加eval

BEGIN {
   eval { require IO::Uncompress::Gunzip }
      or die "Error: IO::Uncompress::Gunzip not installed: $@";

   import IO::Uncompress::Gunzip qw( gunzip $GunzipError );
}

您还可以通过使用eval EXPR 而不是eval BLOCK 来延迟use 的编译(并因此评估):

BEGIN {
   eval 'use IO::Uncompress::Gunzip qw( gunzip $GunzipError ); 1'
      or die "Error: IO::Uncompress::Gunzip not installed: $@";
}

(我希望有一种很好的方法来确定是否安装了模块。即使第一个解决方案也会捕获其他错误,第二个甚至更多。)

【讨论】:

    【解决方案2】:

    这里发生的情况是模块在编译时是used,而不管它是否在eval 块内。

    这也是为什么naab's suggestioneval BLOCK 形式更改为eval EXPR 形式也有效的原因;表达式在运行时进行评估。 将use 更改为require 将尝试在运行时加载模块:

    eval {
        require IO::Uncompress::Gunzip;
        IO::Uncompress::Gunzip->import( qw/gunzip $GunzipError/ ) ;
    };
    if ($@) {
        die "Error: IO::Uncompress::Gunzip not installed: $@";
    }
    

    输出

    错误:IO::Uncompress::Gunzip not installed: Can't locate IO/Uncompress/Gunzip.pm in @INC (@INC contains: C:/Perl/site/lib C:/Perl/lib .)在 - 第 2 行。

    【讨论】:

    • 没有必要将加载移动到运行时,您也不想将加载移动到运行时。如果这样做,您将在访问 $GunzipError 时遇到严格错误。
    • @ikegami :为我工作(一直是qw//-ed)
    • 那么你的测试就坏了。 Global symbol "$GunzipError" requires explicit package name at -e line 1 是从 perl -e'use strict; eval { require IO::Uncompress::Gunzip; IO::Uncompress::Gunzip->import( qw/gunzip $GunzipError/ ); }; die $@ if $@; $GunzipError;' 收到的
    • (如果gunzip 有原型,你也会遇到问题,但它没有。)
    • @ikegami :您的意思是说将您的测试包装在BEGIN 块中会使$GunzipError 定义或免除限制吗?
    【解决方案3】:

    查看 Class::Load 的 try_load_class (CPAN)

    use Class::Load;
    die "Error: IO::Uncompress::Gunzip not installed" if 
        (! try_load_class (IO::Uncompress::Gunzip));
    

    但据我所知,您不能使用 Class::Load 导入 qw(gunzip $GunzipError)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-09-03
      • 2021-10-26
      • 1970-01-01
      • 2010-11-08
      • 2014-11-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多