我刚开始使用对象,并且不明白为什么Try::Tiny不会catch
我的try
语句中的错误。以下是我正在尝试做的一个示例:
use strict;
use warnings;
use Net::FTP;
use Try::Tiny;
my $TIMEOUT = 5;
my $HOST = 'replace_with_hostname';
my $USER = 'replace_with_username';
my $PASS = 'replace_with_password';
my @ERRORS;
my $ftp = undef;
sub my_sub {
my $err = shift;
push(@ERRORS,$err);
goto END;
}
try {
local $SIG{ALRM} = sub { die "new\n" };
alarm $TIMEOUT;
$ftp = Net::FTP->new($HOST, Passive=>1, DEBUG=>3, Timeout=>2);
alarm 0;
}
catch {
die $_ if $_ ne "new\n";
my_sub("FTP: cannot connect to [$HOST]");
};
try {
local $SIG{ALRM} = sub { die "login\n" };
alarm $TIMEOUT;
$ftp->login($USER,$PASS);
alarm 0;
}
catch {
die $_ if $_ ne "login\n";
my_sub("FTP: cannot cannot log in");
};
END: {
if (@ERRORS) {
print "$ERRORS[0]\n";
exit -1;
}
print "Success\n";
exit 0;
}
我正在使用goto
函数,因为我最终会有用于WebDAV和CMIS测试的块,并希望在我点击END
之前捕获所有错误。我可以通过更改try-catch
块来使前面的操作符合我的要求:
try {
local $SIG{ALRM} = sub { die "new\n" };
alarm $TIMEOUT;
$ftp = Net::FTP->new($HOST, Passive=>1, DEBUG=>3, Timeout=>2)
or my_sub("FTP: cannot connect to [$HOST]");
alarm 0;
}
catch {
die $_ if $_ ne "new\n";
};
然而,在这两种情况下,我都觉得我没有好好使用Try::Tiny。
当然,我真正想做的是将try-catch
块放在函数中,就像sid_com did一样。这对我不起作用:
sub try_f {
my $cmd = shift;
my $msg = shift;
try {
local $SIG{ALRM} = sub { die "timeout '$cmd'\n" };
alarm $TIMEOUT;
\$cmd or my_sub($msg);
alarm 0;
}
catch {
die $_ if $_ ne "timeout '$cmd'\n";
};
} # sub
try_f("$ftp = Net::FTP->new(Host=>$HOST, Passive=>1)", "FTP: cannot connect to [$HOST]");
try_f("$ftp->login($USER,$PASS)", "FTP: cannot cannot log in");
错误说$ftp
是未初始化的值,但我不知道如何解决这个问题。
use strict;
use warnings;
use Net::FTP;
use Try::Tiny;
my $HOST = 'replace_with_hostname';
my $USER = 'replace_with_username';
my $PASS = 'replace_with_password';
my @ERRORS;
my $ftp = undef;
sub try_f {
my $timeout = shift;
my $command = shift;
my $message = shift;
my $label = shift;
try {
local $SIG{ALRM} = sub { die "timeout\n" };
alarm $timeout;
$command->() or die "module\n";
alarm 0;
}
catch {
if ( $_ eq "module\n" || $_ eq "timeout\n" ) {
push(@ERRORS,"$message: $_");
goto $label;
}
die $_;
};
}
FTP_BLOCK: {
try_f(4, sub { $ftp = Net::FTP->new($HOST, Passive=>1, Debug=>3) }, "FTP: cannot connect to [$HOST]", 'END');
try_f(2, sub { $ftp->login($USER,$PASS) }, "FTP: cannot log in", 'END');
}
END: {
if (@ERRORS) {
foreach my $e (@ERRORS) { print "$e"; }
exit -1;
}
print "Success\n";
exit 0;
}
答案 0 :(得分:4)
Net::FTP->new
在出错时没有die
。相反,它只返回undef
。因此,Try::Tiny
无法确定出错的地方,并且catch
块未执行。
而不是my_sub
,请使用
$ftp = Net::FTP->new($HOST, Passive=>1, DEBUG=>3, Timeout=>2) or die $@;
Try :: Tiny文档说$@
在catch
区块中不会出现错误,但Net::FTP->new
表示会出错如果它返回undef
则在那里发送消息。这就是为什么你可以die
在try
区块中使用消息<(如果需要,您也可以在这种情况下使用自己的消息)。
同样,login
returns a false value on error,因此您需要添加“or die
”语句(遗憾的是,login
似乎没有出现错误消息)。
答案 1 :(得分:2)
您正尝试在字符串中传递代码:
try_f("$ftp = Net::FTP->new(Host=>$HOST, Passive=>1)", "FTP: cannot connect to [$HOST]");
\$cmd or my_sub($msg);
那不行。
我建议改为使用sub { }
来创建匿名代码引用吗?
try_f( sub { $ftp = ..... } );
然后再
$cmd->() or my_sub($msg);