有几次我遇到了忘记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";
}
Run Code Online (Sandbox Code Playgroud)
出于某种原因,该脚本可以正常运行,而没有任何提示try。没有Undefined subroutine错误。这使我想知道为什么未捕获我提出的异常。
为什么这会无声地工作而没有错误?
编辑
我也查看了符号表:
say "$_: %main::{ $_ }" for keys %main::;
Run Code Online (Sandbox Code Playgroud)
没有发现try。我也尝试像main::try上面的脚本一样调用它,它也没有引起错误。
zdi*_*dim 10
这是由于间接对象语法引起的,并且是此示例上更为详尽的变体。
该“间接对象符号”允许代码
PackageName->method(@args);
Run Code Online (Sandbox Code Playgroud)
被写成
method PackageName @args;
Run Code Online (Sandbox Code Playgroud)
因此,“ 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";
}
Run Code Online (Sandbox Code Playgroud)
作为perl -MO=Deparse script.pl应该呈现什么运行一个很接近的近似:
使用警告;
使用严格
使用功能“说”;
尝试{
call_a('x')
}做{
死了“实际上死了”
}->抓住;
子call_a {
使用警告;
使用严格
使用功能“说”;
死“是死”;
}
undef_sub.pl语法确定
嵌套的间接对象语法显然太多了,Deparse因此method BLOCK LIST在输出中仍然保留形式。等效代码可以拼写为
(do { call_a('x') })->try( (do { die("ACTUALLY die") })->catch() );
Run Code Online (Sandbox Code Playgroud)
在这种情况下更简单
call_a('x')->try( die("ACTUALLY die")->catch() );
Run Code Online (Sandbox Code Playgroud)
因此,原始代码被解释为有效的语法(!),并且()之后的块trycall_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";
}
Run Code Online (Sandbox Code Playgroud)
没有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
Run Code Online (Sandbox Code Playgroud)
现在采用简单method {} args语法(args本身也Deparse以间接对象表示法显示)。等效代码是
call_a('x')->try( say("NO DONT die")->catch() );
Run Code Online (Sandbox Code Playgroud)
首先运行call_a(),然后返回,然后在try方法调用中运行参数列表的代码。我们没有遇到die,实际的运行
没有死 不死 在没有包或对象引用的情况下无法调用方法“ catch”
因此,现在出现了“捕获”方法的问题。
感谢池上的评论
如果上面的块要返回确实具有方法的包(或对象引用)的名称,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" }
Run Code Online (Sandbox Code Playgroud)
现在我们有等效的
call_a('x')->try( do { say("NO DONT die"); 'Catch' }->catch() );
Run Code Online (Sandbox Code Playgroud)
与输出
没有死 不死 在Catch :: catch中 在undef_sub.pl第14行中没有包或对象引用的情况下,无法调用方法“ try”。