是的,问题出在我正在使用的库上,不,我无法修改它。我需要一个解决方法。

基本上,我正在处理一个写得不好的 Perl 库,当读取文件时遇到特定错误情况时,该库会以“die”退出。我从一个程序中调用这个例程,该程序循环访问数千个文件,其中一些文件是错误的。坏文件时有发生;我只想让我的例程记录一个错误并继续。

如果我可以修改库,我只需更改

die "error";

到一个

print "error";return;

, , 但是我不能。有什么方法可以调整例程,以便坏文件不会使整个过程崩溃?

后续问题:使用“eval”来处理容易崩溃的调用效果很好,但是如何在该框架内设置对可捕获错误的处理?来描述:

我有一个子例程,有时会多次调用该库,该库有时会崩溃。我没有使用 eval{} 来处理此子例程中的每个调用,而是让它终止,并在调用我的子例程的级别上使用 eval{}:

my $status=eval{function($param);};
unless($status){print $@; next;}; # print error and go to next file if function() fails

但是,我可以并且确实在 function() 中捕获了一些错误条件。在子例程和调用例程中设计错误捕获的最正确/优雅的方法是什么,以便我对捕获和未捕获的错误都获得正确的行为?

有帮助吗?

解决方案

您可以在一个eval包裹。参见:

perldoc -f eval

例如,你可以写:

# warn if routine calls die
eval { routine_might_die }; warn $@ if $@;

这会变成致命错误变成警告,这或多或少是你的建议。如果die被调用,$@包含传递给它的字符串。

其他提示

是否有陷阱 $SIG{__DIE__}?如果是的话,那么它比你更本地化。但有几个策略:

  • 您可以调用它的包并 覆盖 死:

    package Library::Dumb::Dyer;
    use subs 'die';
    sub die {
        my ( $package, $file, $line ) = caller();
        unless ( $decider->decide( $file, $package, $line ) eq 'DUMB' ) {
            say "It's a good death.";
            die @_;
       }
    } 
    
  • 如果没有的话可以 陷阱 它。(在页面上查找 $SIG,markdown 不处理完整链接。)

    my $old_die_handler = $SIG{__DIE__};
    sub _death_handler { 
        my ( $package, $file, $line ) = caller();
        unless ( $decider->decide( $file, $package, $line ) eq 'DUMB DIE' ) {
            say "It's a good death.";
            goto &$old_die_handler;
        }
    }
    $SIG{__DIE__} = \&_death_handler;
    
  • 您可能需要扫描图书馆,找到它的子目录 总是 调用,并用它来加载你的 $SIG 通过覆盖处理程序 that.

    my $dumb_package_do_something_dumb = \&Dumb::do_something_dumb;
    *Dumb::do_something_dumb = sub { 
        $SIG{__DIE__} = ...
        goto &$dumb_package_do_something_dumb;
    };
    
  • 或者重写它的内置函数 总是 打电话...

    package Dumb; 
    use subs 'chdir';
    sub chdir { 
        $SIG{__DIE__} = ...
        CORE::chdir @_;
    };
    
  • 如果其他方法都失败了,你可以用以下方法鞭打马的眼睛:

    package CORE::GLOBAL;
    use subs 'die';
    
    sub die { 
        ... 
        CORE::die @_;
    }
    

这将覆盖 在全球范围内,这是您返回的唯一途径 die 是将其解决为 CORE::die.

将其组合起来会起作用。

虽然改变die不管芯具有如在其他的答案中所示的特定的解决方案,一般可以总是覆盖其他包中的子程序。你完全不改变原来的来源。

首先,让你获得所有的原始定义的装入原包装。一旦原始就位,就可以重新定义麻烦子程序:

 BEGIN {
      use Original::Lib;

      no warnings 'redefine';

      sub Original::Lib::some_sub { ... }
      }

您甚至可以剪切和粘贴的原始定义和调整你所需要的。这不是一个很好的解决方案,但如果你不能改变原始来源(或希望更改原始之前尝试的东西),它可以工作。

除此之外,您可以将原始源文件复制到你的应用程序一个单独的目录。因为您可以控制目录,你可以在它编辑的文件。您修改副本,并通过添加目录到Perl的模块搜索路径加载:

use lib qw(/that/new/directory);
use Original::Lib;  # should find the one in /that/new/directory

您复制棍棒甚至周围是否有人更新原始模块(尽管你可能需要合并更改)。

我说说这个颇有几分在掌握的Perl ,在这里我展示一些其他技术做之类的东西。诀窍是更不打破东西。你怎么不打破东西取决于你在做什么。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top