有几次我遇到了忘记在脚本中加载Try::Tiny
模块而仍然使用try-catch
块的情况,如下所示:>
#!/usr/bin/env perl
use strict;
use warnings;
try {
call_a( 'x' );
} catch {
die "ACTUALLY die $_";
};
sub call_a {
die "Yes, I will";
}
由于某种原因,该脚本可以正常运行,而没有任何提示try
的提示。没有Undefined subroutine
错误。这使我想知道为什么未捕获到我提出的异常。
为什么它会无声无息地正常工作?
编辑
我也查看了符号表:
say "$_: %main::{ $_ }" for keys %main::;
,发现没有try
。我也尝试在上面的脚本中将其称为main::try
,并且也没有引起错误。
答案 0 :(得分:10)
这是由于间接对象语法引起的,并且是this example上更为详尽的变体。
"indirect object notation"允许代码
PackageName->method(@args);
写为
method PackageName @args;
因此,“ try”和“ catch”这两个词无关紧要。有趣的是语法更加复杂和扩展,分为两个部分,每个部分都使用间接对象表示法。
所讨论的代码实际上具有method BLOCK LIST
形式,但这也通过间接对象语法进入(do BLOCK)->method(LIST)
中,其中do BLOCK
需要产生一个包名或一个有福的(对象)引用,以进行有意义的方法调用。在下面的Deparse
输出中可以看到。
在此代码上使用B::Deparse编译器后端(通过O模块)
use strict;
use warnings;
use feature 'say';
try { call_a( 'x' ) }
catch {
die "ACTUALLY die";
#say "NO DONT die";
};
sub call_a {
die "Yes it dies";
#say "no die";
}
perl -MO=Deparse script.pl
应该显示出运行情况的非常近似值:
use warnings; use strict; use feature 'say'; try { call_a('x') } do { die 'ACTUALLY die' }->catch; sub call_a { use warnings; use strict; use feature 'say'; die 'Yes it dies'; } undef_sub.pl syntax OK
对于Deparse
来说,嵌套的间接对象语法显然太多了,仍然在输出中保留method BLOCK LIST
形式。等效代码可以拼写为
(do { call_a('x') })->try( (do { die("ACTUALLY die") })->catch() );
在这种情况下更简单
call_a('x')->try( die("ACTUALLY die")->catch() );
因此,原始代码被解释为有效语法(!),并且{em> try
(call_a('x')
)之后的块的内容首先运行 ---程序死了,再也没有去寻求“方法” try
。
将示例更改为
会变得更加有趣。use strict;
use warnings;
use feature 'say';
try { call_a( 'x' ) }
catch {
#die "ACTUALLY die";
say "NO DONT die";
};
sub call_a {
#die "Yes it dies";
say "no die";
}
在任何地方都没有die
-。使用-MO=Deparse
运行它以查看
use warnings;
use strict;
use feature 'say';
try {
call_a('x')
} (catch {
say 'NO DONT die'
} );
sub call_a {
use warnings;
use strict;
use feature 'say';
say 'no die';
}
undef_sub.pl syntax OK
现在采用了一种简单的method {} args
语法(args
本身也由Deparse
用间接对象表示法表示)。
等效代码为
call_a('x')->try( say("NO DONT die")->catch() );
首先call_a()
到达的位置,然后返回,然后try
方法调用中的参数列表的代码接下来运行。我们没有遇到die
,实际的运行情况是
no die NO DONT die Can't call method "catch" without a package or object reference at ...
所以现在出现了方法“捕获” 的问题。
感谢ikegami的评论
如果要在上面的块返回的包(或对象引用)的名称确实具有方法catch
,则最终也将尝试使用try
use strict;
use warnings;
use feature 'say';
BEGIN {
package Catch;
sub catch { say "In ", (caller(0))[3] };
$INC{"Catch.pm"} = 1;
};
use Catch;
try { call_a( 'x' ) }
catch {
say "NO DONT die";
"Catch";
};
sub call_a { say "no die" }
现在我们有等效的
call_a('x')->try( do { say("NO DONT die"); 'Catch' }->catch() );
与输出
no die NO DONT die In Catch::catch Can't call method "try" without a package or object reference at undef_sub.pl line 14.