Perl 意外行为:croak 与 try catch

2024-01-18

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

在我看来,这是一个意想不到的行为,因为它改变了原始异常的位置并使得调试变得困难(应该说在第 13 行处死亡。)

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

由于不知道如何在堆栈中调用我的代码,我现在开始避免使用 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
}

Output: die at line 10.


这是预期的行为Carp https://perldoc.perl.org/Carp

[...] 使用carp() or croak()它将错误报告为来自调用模块的位置。 [...] 不能保证这就是错误所在,但这是一个很好的有根据的猜测。

所以在调用模块的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";

Prints



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

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

如果子抛出使用die那么这将被报告在line 11,什么是正常行为die https://perldoc.perl.org/functions/die,以及您似乎所期望的。

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.

如果你想confess一个对象注意此时鲤鱼有极限 https://perldoc.perl.org/Carp#BUGS接着就,随即

The Carp例程当前不处理异常对象。如果使用作为引用的第一个参数调用,它们只需调用die() or warn(), 作为适当的。

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.


我得到同样的行为eval,通过替换 try-catch 和$_ above

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

打印与上面完全相同


虽然上面的内容很清楚并且行为符合预期,但在问题的示例中确实看到了奇怪的事情:错误是从整个 try-catch 语句报告的,即。在其右大括号处,即第 10 行所在的位置。 (这trysub 是原型化的,整个 try-catch 是一个语法辅助,相当于调用try这需要一个匿名潜艇,甚至更多。请参阅 ikegami 的评论和文档。另请参阅这个帖子 https://stackoverflow.com/a/57997918/4653379有关其语法的更多信息。)

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

明确的目的croak将在库中使用,以便用户可以看到他们(用户)代码中的哪个点以触发错误的方式调用了库。 (尽管die会指向检测到错误的地方,所以in库,很可能对用户来说毫无用处。但读die and Carp相关复杂性的文档。)

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

这不会发生,如果main::foo() with croakinside 是从一个(复杂的)语句中调用的main::,所以这似乎是由于命名空间的 try-catch 混合造成的。 (另一方面,try-catch 糖会向调用堆栈添加一个匿名子进程,这肯定也会把事情搞混。)

实际上,我会说:总是使用croak超出模块(否则使用die),或者,如果您想模仿基于异常的代码,最好使用confess和/或您的异常类层次结构。


Even just like die ExceptionClass->new(...);

请记住,在例外方面,Perl 只有孤独的die, and eval。对于更多结构,您需要全部实现,或者使用类似的框架异常::类 https://metacpan.org/pod/Exception::Class or 可投掷 https://metacpan.org/pod/Throwable


By writing and using a method that generates a plain string with useful information from the object, for Carp::confess $obj->stringify.

Or by 超载 https://perldoc.perl.org/overload the ""类的(引用)运算符,因为它在以下情况下使用confess-ing 一个对象(字符串上下文),对于Carp::confess $obj;无论如何,这很好。

两者的基本示例:

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

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

其中可以直接编写匿名子集,而不是对命名子集的引用sub.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Perl 意外行为:croak 与 try catch 的相关文章

随机推荐

  • 修复 COM 引用:类型库导入程序无法转换成员 DISPPARAMS.rgvarg 的签名

    我有一个构建服务器 我在其中构建 Visual Studio 扩展 我最近迁移到另一台服务器 现在我收到以下警告 C Windows Microsoft NET Framework v4 0 30319 Microsoft Common t
  • 在 Eclipse 中调试时如何跳过 JRE 代码?

    在 Eclipse 中调试时 我单步执行 F5 语句 如下所示 encryptedBytes LightWeightEncryptor encrypt messageBytes password toCharArray 调试器进入 JRE
  • 从逗号分隔的字符串中批量插入

    我有一个表 其中一列包含以下数据 abc 2 2 34 5 3 2 34 32 2 3 2 2 def 2 2 34 5 3 2 34 32 2 3 2 2 我想获取这些数据并将其插入到另一个表中 使用逗号作为分隔符 就像您可以指定FIEL
  • C# TCP 套接字错误 - 10060

    我有一个 Windows 服务作为服务器 我以 localhost 作为客户端运行一个 Windows 窗体应用程序 这两个程序都使用 TCP 套接字连接来发送 接收数据 服务器侦听端口 8030 程序运行正常 但是 当我增强客户端程序以在
  • 在画布上手动逐像素绘制一个圆圈[关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 我正在尝试做一些复杂的效果 为了做到这一点 我必须将其分解为各个组件 我可以在此基础上进行构建 并希望它们能够组合在一起 现在在画布上画一个
  • 浏览器将边框值截断为整数

    每当非整数像素值用于元素的边框时 浏览器都会将该值截断为整数 为什么会这样呢 我知道边境不会actually占用像素的一部分 但这些类型的值有时与其他值结合使用以形成完整像素 例如 宽度为 1 6px 的左右边框应导致元素的总宽度增加 3p
  • Console.Clear() 闪烁

    while true Console Clear for int row 0 row lt 50 row for int col 0 col lt 50 col Console Write world row col Console Wri
  • 当原始对象更改时,绑定不会更新

    我想我误解了 Angular 中数据绑定和作用域的工作原理 或者我对 Javascript 有一些误解 我希望有人能帮助我 假设我有一个工厂 它有一个对象 并为其定义了一个 getter setter app factory myFacto
  • Tkinter 滚动条不滚动

    我正在尝试创建一个带有两个画布和一个滚动条的图形用户界面 同时穿过这两个画布 作为另一个项目的测试 我创建了根 两个画布 并使用网格方法将一些标签固定到每个画布上 并创建了滚动条 但是 当我运行该程序时 滚动条会移动 但窗口的内容根本没有改
  • 在 Java 中管理 XAdES 签名的库 [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找一个允许创建和验证 XAdES 签名的 Java 库 格式越多越好 XAdES BES XAd
  • 二维unordered_map

    typedef boost unordered map
  • 为什么即使对象指针在多重继承中不同,情况也是一样的?

    当使用多重继承时 C 必须维护多个 vtable 这导致对公共基类有 多个视图 这是一个代码片段 include stdafx h include
  • 具有非静态 lambda 成员的类不能使用默认模板参数吗?

    这个小测试程序 include
  • 通过 .htaccess 从 URL 中删除双斜杠或更多斜杠时出现问题

    我使用以下 htaccess 规则从 Web url 中删除双斜杠或多个斜杠 remove double more slashes in url RewriteCond REQUEST URI RewriteRule 1 2 R 301 L
  • 选定列的高图表不同颜色

    Highcharts 中不同的选定列是否可以有不同的颜色 这是我想做的事情的草图 http jsfiddle net jZmYW 4 http jsfiddle net jZmYW 4 选择一个点 列 时 它应该具有特定的颜色 我尝试通过为
  • XSLT 字符串替换

    我不太了解 XSL 但我需要修复这段代码 我已经减少了它以使其更简单 我收到这个错误 无效的 XSLT XPath 函数 在这条线上
  • Java MVC Web开发框架?

    我想用java开发一个网站 但我在java web开发方面是绝对的初学者 我想使用一个使用 MVC 模式和 Ajax 的框架 我做了一些搜索 发现 Spring 或 Struts 合适 但我不确定 您能推荐一个框架吗 游戏框架 http w
  • .NET - 从非托管数组复制到非托管数组

    我一直在查看 Marshal 类 但似乎找不到允许我从非托管数组 IntPtr 复制到另一个非托管数组 IntPtr 的方法 使用 NET 可以实现这一点吗 您还可以通过 DllImport RtlMoveMemory 来完成工作 DllI
  • 如何使用谷歌翻译应用程序

    我编写了有关字典句子的程序 我希望有功能可以在我的应用程序中转到 谷歌翻译 应用程序 我该如何使用它 我应该导入什么东西吗 据我所知 谷歌翻译 Android 应用程序没有公开任何标准Intent是你可以使用的 很遗憾 但同时也很奇怪 你会
  • Perl 意外行为:croak 与 try catch

    我看到一些异常指向 catch 块本身 参见下面的示例 在我看来 这是一个意想不到的行为 因为它改变了原始异常的位置并使得调试变得困难 应该说在第 13 行处死亡 如果我使用 die confess 或使用 eval 代替 try catc