gpt4 book ai didi

Perl 意外行为 : croak vs. try catch

转载 作者:行者123 更新时间:2023-12-05 02:01:26 25 4
gpt4 key购买 nike

我看到了一些指向 catch block 本身(结束)的异常(参见下面的示例)。

在我看来,这是一个意外的行为,因为它改变了原始异常的位置并且难以调试(应该说死在第 13 行。)

它显示(正确的)第 13 行,如果我使用 die/confess 或使用 eval 而不是 try-catch。

不知道我的代码将如何在堆栈中被调用,我现在开始避免使用 croak。你怎么看?我做对了吗?还是有办法改进?

最好的问候,史蒂夫

use Carp;
use Try::Tiny;

try {
foo();
}
catch {
# do something before die
die $_;
}; # this is line 10

sub foo {
croak 'die'; # this is line 13
}

输出:死于第 10 行。

最佳答案

这是 Carp 的预期行为

[...] use carp() or croak() which report the error as being from where your module was called. [...] There is no guarantee that that is where the error was, but it is a good educated guess.

所以在调用模块的sub的地方报错,这才是用户想要的

use warnings;
use strict;
use feature 'say';

use Try::Tiny;

package Throw {
use warnings;
use Carp qw(croak confess);

#sub bam { die "die in module" }; # l.11
sub bam { croak "croak in module" };
1;
};

try {
Throw::bam(); # l.17
}
catch {
say "caught one: $_";
die "die in catch: $_";
};
say "done";

打印

caught one:   croak in module at exceptions.pl line 17.die in catch: croak in module at exceptions.pl line 17.

If the sub throws using die then this is reported at line 11, what is the normal behavior of die, and what you seem to expect.

If any of this is unclear or suboptimal then better use confess and nicely get a full stacktrace. Also, if you wish more exception-based-like code behavior, can put together an exception/error class and throw its object, designed and populated as desired.

If you want to confess an object note that at this time Carp has limits with that

The Carp routines don't handle exception objects currently. If called with a first argument that is a reference, they simply call die() or warn(), as appropriate.

One way then would be to confess a stringification of the object, getting at least both a full stack backtrace and whatever is in the object.


I get the same behavior with eval, by replacing try-catch and $_ above

eval { 
Throw::bam();
};
if ($@) {
say "caught one: $@";
die "die in catch: $@";
};

打印出来和上面完全一样


虽然上面很清楚并且表现符合预期,但在问题的示例中确实看到了一件奇怪的事情:错误是从整个 try-catch 语句报告的,即。在它的右大括号处,第 10 行所在的位置。 (try sub 是原型(prototype),整个 try-catch 是一种语法辅助,相当于调用 try 接受匿名 sub,然后可能更多。请参阅 ikegami 的评论和文档。另请参阅 this post 以获取更多关于它的语法。)

这很奇怪,因为对 croaking sub 的调用是 foo()try里面声明和这一行应该被报告,可以通过运行带有 -MCarp::Always 的脚本来确认什么.但是在这个答案的代码中,调用 Throw::bam 的行确实有报道——为什么会有这种差异?

croak的明确目的将在库中使用,以便用户可以看到他们(用户)代码中的哪一点以触发错误的方式调用了库。 (虽然 die 会指向检测到错误的位置,因此库中,很可能对用户无用。但请阅读 dieCarp 文档以了解相关的复杂性。)

不明显的是当croak在与 main::foo() 相同的命名空间 ( try-catch ) 中发出在它自己的命名空间(Try::Tiny)中,事情变得困惑,并报告其声明的结尾。这可以通过添加 foo() 来检查到我上面的代码并调用它(而不是来自模块的子),我们得到了问题的行为重现。

如果 main::foo() 则不会发生这种情况与 croak inside 是从 main:: 中的(复杂)语句调用的,所以这似乎是由于命名空间的 try-catch 混淆。 (另一方面,try-catch 糖向调用堆栈添加了一个匿名子,这肯定也会混淆。)

实际上,我会说:始终使用 croak在模块之外(否则使用 die ),或者,如果您想模仿基于异常的代码,则更好,使用 confess和/或您的异常类层次结构。


甚至就像die ExceptionClass->new(...);

请记住,在异常方式中,Perl 只有孤独的 die , 和 eval .对于更多结构,您需要全部实现,或使用像 Exception::Class 这样的框架或 Throwable


通过编写和使用一种方法,该方法可以生成包含来自对象的有用信息的纯字符串,对于 Carp::confess $obj->stringify .

或通过overloading ""该类的(引用)运算符,因为它在 confess 时被使用-ing 对象(字符串上下文),用于 Carp::confess $obj ;无论如何,这很好。

两者的基本示例:

use overload ( q("") => \&stringify );

sub stringify {
my $self = shift;
join ", ", map { "$_ => " . ( $self->{$_} // 'undef' ) } keys %$self
}

可以直接写一个匿名 sub 而不是对命名子的引用.

关于Perl 意外行为 : croak vs. try catch,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66527342/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com