如何在 Perl 中创建和抛出异常?

How to create and to throw exceptions in Perl?

例如,php 有类似 InvalidArgumentException 的异常和自定义消息 'Current group not found'。

而且我可以在代码中抛出这个异常。

if ($groupId === 0) {
    throw new InvalidArgumentException('Current group not found');
}

我可以继承这个异常并创建另一个子异常。

异常在 Perl 中是如何工作的?

有多种方法可以做到这一点,但它们没有直接内置到 Perl 中。

最简单的就是dieeval {}去抓。

eval {
  die "in a fire";
};
if ($@) {
  print "something went wrong";
}

如果你想要try,同样有多种选择。最常见的是 Try::Tiny.

use Try::Tiny;

try {
  die;
} catch {
  print $_;
};

如果您想走在前沿,Paul Evans 进行了一项研究,将实际关键字 try 放入 Perl 代码中。他以 Syntax::Keyword::Try 的形式发布了这个原型,并且最近就它进行了各种讨论,包括 2021 年在 Fosdem 上的讨论。

现在对于实际的异常,正如典型的 Perl 一样,有几种方法可以做到这一点。

die 可以将对象作为参数而不仅仅是字符串,因此您几乎可以模拟其他语言的行为。

Throwable is probably what I would go for today. You can easily create lots of these classes on the fly with Throwable::Factory.

use Throwable::Factory
  InvalidArgumentException => [qw( $id )];

sub foo {
  my $group_id = shift;
  unless ($group_id) {
    InvalidArgumentException->throw('Current group not found', id => $group_id);
  }
}

稍后要抓住它,您可以这样做:

use Try::Tiny;

try {
  foo(0);
} catch {
  warn $_;
};

我喜欢使用 JT Smith 的 Ouch 模块,尤其是对于 Web 应用程序。这个例子结合了 Ouch 和 TryTiny

use Ouch;
use Try::Tiny;
sub ProcessFiles {    die "Help, help, I'm being repressed";    }

sub DoLotsOfStuff {
    try {
        ProcessFiles();
    } catch {
        ouch 'That module/sub gave me an err', "died: $_";
    };
}
sub Driver {
    try {
        DoLotsOfStuff();
    } catch {
        if (hug($_)) {
            ouch 404, "Driver: $_"; # the caller wants a numeric code
        }
    }
}

try {
    Driver();
} catch {
    if (kiss(404,$_)) {
        ouch 404, "CallAPI: $_";
    }
}