Ed *_*yer 30 error-handling perl die
是的,问题出在我正在使用的库中,不,我无法修改它.我需要一个解决方法.
基本上,我正在处理一个写得很糟糕的Perl库,当遇到读取文件的某个错误条件时,它会以'die'退出.我从一个程序中调用这个例程,该程序循环遍历数千个文件,其中一些文件很糟糕.坏文件发生; 我只想让我的例程记录错误并继续前进.
如果我可以修改库,我只需更改
die "error";
Run Code Online (Sandbox Code Playgroud)
到了
print "error";return;
Run Code Online (Sandbox Code Playgroud)
, 但是我不能.有什么方法可以解决这个例程,以便坏文件不会崩溃整个过程?
关注问题:使用"eval"来解决容易崩溃的调用很有效,但是如何在该框架内设置可捕获错误的处理?来描述:
我有一个子程序调用库 - 崩溃 - 有时很多次.而不是使用eval {}在这个子例程中调用每个调用,我只是让它死掉,并在调用我的子例程的级别上使用eval {}:
my $status=eval{function($param);};
unless($status){print $@; next;}; # print error and go to next file if function() fails
Run Code Online (Sandbox Code Playgroud)
但是,我可以在函数()中捕获错误条件.在子例程和调用例程中设计错误捕获的最恰当/优雅的方法是什么,以便我获取捕获和未捕获错误的正确行为?
Jon*_*son 67
你可以将它包装成一个eval.看到:
perldoc -f eval
Run Code Online (Sandbox Code Playgroud)
例如,你可以写:
# warn if routine calls die
eval { routine_might_die }; warn $@ if $@;
Run Code Online (Sandbox Code Playgroud)
这会将致命错误转变为警告,这或多或少是您的建议.如果die被调用,则$@包含传递给它的字符串.
Axe*_*man 27
陷阱$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 @_;
}
}
Run Code Online (Sandbox Code Playgroud)如果没有,可以捕获它.(在页面上查找$ 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;
Run Code Online (Sandbox Code Playgroud)您可能必须扫描库,找到它始终调用的子,并使用它来$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;
};
Run Code Online (Sandbox Code Playgroud)或者覆盖它总是调用的内置函数......
package Dumb;
use subs 'chdir';
sub chdir {
$SIG{__DIE__} = ...
CORE::chdir @_;
};
Run Code Online (Sandbox Code Playgroud)如果一切都失败了,你可以用这个鞭打马的眼睛:
package CORE::GLOBAL;
use subs 'die';
sub die {
...
CORE::die @_;
}
Run Code Online (Sandbox Code Playgroud)这将全局覆盖die,你可以回来的唯一方法die是将其作为CORE::die.
这种方法的某种组合可行.
虽然将其更改die为not die有一个特定的解决方案,如其他答案所示,通常您可以始终覆盖其他包中的子例程.您根本不更改原始来源.
首先,加载原始包,以便获得所有原始定义.原件到位后,您可以重新定义麻烦的子程序:
BEGIN {
use Original::Lib;
no warnings 'redefine';
sub Original::Lib::some_sub { ... }
}
Run Code Online (Sandbox Code Playgroud)
您甚至可以剪切和粘贴原始定义并调整所需内容.这不是一个很好的解决方案,但是如果你不能改变原始来源(或者想要在更改原始内容之前尝试一些东西),它就可以工作了.
除此之外,您还可以将原始源文件复制到应用程序的单独目录中.由于您控制该目录,因此可以编辑其中的文件.您可以通过将该目录添加到Perl的模块搜索路径来修改该副本并加载它:
use lib qw(/that/new/directory);
use Original::Lib; # should find the one in /that/new/directory
Run Code Online (Sandbox Code Playgroud)
即使有人更新了原始模块,您的副本仍然存在(尽管您可能需要合并更改).
我在Mastering Perl中讨论了这个问题,在那里我展示了一些其他技术来做这种事情.诀窍是不要破坏更多的东西.你怎么不打破东西取决于你在做什么.
| 归档时间: |
|
| 查看次数: |
13727 次 |
| 最近记录: |