perl - 为什么“尝试”不会导致未定义的子程序错误?
问题描述
有几次我遇到了忘记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
上面的脚本调用它,它也没有导致错误。
解决方案
这是由于间接对象语法,并且是此示例的更精细的变体。
“间接对象表示法”允许代码
PackageName->method(@args);
写成
method PackageName @args;
所以“try”和“catch”这两个词无关紧要。这里有趣的一点是更多涉及和扩展的语法,有两个部分,每个部分都使用这种间接对象表示法。
有问题的代码实际上有method BLOCK LIST
形式,但这也通过间接对象语法 into (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
应该显示运行的非常接近的近似值:
使用警告; 使用严格; 使用功能“说”; 尝试 { call_a('x') } 做 { 死'实际上死' }->捕捉; 子调用_a { 使用警告; 使用严格; 使用功能“说”; die '是的,它死了'; } undef_sub.pl 语法OK
嵌套的间接对象语法显然太多了Deparse
,仍然method BLOCK LIST
在输出中留下形式。等效代码可以拼写为
(do { call_a('x') })->try( (do { die("ACTUALLY die") })->catch() );
在这种情况下更简单
call_a('x')->try( die("ACTUALLY die")->catch() );
因此,原始代码被解释为有效的语法 (!),它是( )之后的块的内容首先运行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
我们没有遇到 adie
并且实际运行如下
不死 不,不要死 不能在没有包或对象引用的情况下调用方法“catch”...
所以现在确实出现了“catch”方法的问题。
感谢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() );
与输出
不死 不,不要死 在 Catch::catch 中 无法在 undef_sub.pl 第 14 行调用没有包或对象引用的方法“try”。
推荐阅读
- javascript - Laravel 6.0 Stripe:必须提供来源或客户
- javascript - 学习如何使用 ES6 导入和模块获取引用错误
- python-3.x - 使用神经结构化学习的 fit_generator 问题
- ajax - 在 CodeIgniter 中使用 Jquery Ajax 插入记录后打印 Json 数据
- firebase - Firebase UpdateEmail 返回 updateEmail 失败:第一个参数“email”必须是有效字符串
- ios - 在 UIHostingController 中从 SwiftUI 调用函数
- mongodb - MongoDB:使用_id计算过去X天内每天创建的文档
- java - JAVA与服务器php通信
- docker - docker-compose 网络和发布端口
- c# - Unity 脚本不起作用:“找不到脚本类”