当前位置: 首页 > 知识库问答 >
问题:

我想什么时候恢复Perl 6异常?

卜飞鸣
2023-03-14

也许我真正的问题是“这是一个适合学习Perl6的特性吗?”?基于Perl 6 CATCH块是否能够更改词法范围中的变量?,似乎最简单的例子可能超越了简单的例子。

在那个问题上,我正在处理一些看起来很傻的东西,或者用另一种方式更好地解决那个特定的问题,因为我是在玩这个功能,而不是解决一个问题。

有文档记录了警告作为特殊类型的异常(“控制异常”)的用法,在这里,您可以获取消息,如果愿意,可以捕获它,但也可以忽略它,它将自行恢复(尽管我在哪里捕获Perl 6警告控制异常这一点上相当愚蠢?)。

除此之外,我还考虑调用方可以处理被调用方范围之外的故障。例如,重新连接到数据库、修复丢失的目录以及被调用方不负责的其他外部资源问题。

在阅读其他语言中的这类内容时,我们的建议主要是不要使用它们,因为在“现实世界”编程中,人们往往不会真正处理这个问题。

对于C#exception handler resume next的回答似乎是,这是一个糟糕的实践和难看的代码。我当然还没有找到在被调用方中隐藏一堆代码的方法。

我黑了这个例子,尽管我不相信这是一个好方法或者推荐给初学者。程序启动时查找PID文件。如果它找到一个,它会抛出一个异常。处理该异常会检查另一个实例是否仍在运行,这可能会引发不同类型的异常。还有一个是处理文件IO问题的。诀窍是,如果其他程序不运行(但留下了PID文件),X::MyProgram::FoundSemaphore可以恢复。

class X::MyProgram::FoundSemaphore is Exception {
    has $.filename;
    has $.this-pid = $*PID;
    has $.that-pid = $!filename.lines(1);

    method gist {
        "Found an existing semaphore file (pid {.that-pid})"
        }
    }

class X::MyProgram::StillRunning is Exception {
    has $.that-pid;
    has $.os-error;

    method gist {
        "This program is already running (pid {self.that-pid})"
        }
    }

class X::MyProgram::IO::OpenFile is Exception {
    has $.filename;

    method gist {
        "This program is already running (pid {self.that-pid})"
        }
    }

sub create-semaphore {
    state $filename = "$*PROGRAM.pid";
    END { unlink $filename }

    die X::MyProgram::FoundSemaphore.new(
        :filename($filename)
        ) if $filename.IO.e;

    my $fh = try open $filename, :w;

    # open throws Ad::Hoc, which could be more helpful
    die X::MyProgram::IO::OpenFile.new(
        :filename($filename),
        :os-error($!),  # role X::IO-ish
        ) unless $fh;

    $fh.print: $*PID;
    }

BEGIN {
    try {
        CATCH {
            when X::MyProgram::FoundSemaphore {
                my $proc = run qqw/kill -0 {.that-pid}/;
                X::MyProgram::StillRunning.new(
                    :that-pid(.that-pid) ).throw
                    if $proc.so; # exit code is 0, so, True
                unlink .filename;
                .resume;
                }
            default { say "Caught {.^name}"; exit }
            }

        create-semaphore();
        }
    }

sub MAIN ( Int $delay = 10 ) {
    put "$*PID sleeping for $delay seconds";
    sleep $delay;
    }

共有1个答案

金毅
2023-03-14

可恢复异常当然不是我在Perl 6中找到的东西。我想我还没有在“用户空间”代码中使用它们。一个可恢复的异常被证明是实现emit函数的正确方法,该函数用于Supply反应块。集合中使用的ake函数也使用可恢复的异常实现,并且-正如您已经发现的-警告使用它们。

我怀疑最后一个警告是典型的Perl 6用户感兴趣的唯一情况。捕获警告并将其发送到其他地方(可能是发送到日志文件或日志服务器)是需要做的一件相当合理的事情。就学习Perl6而言,这可能是一个明显有用的可恢复异常示例。

我认为重要的是,所有利用Perl 6中可恢复异常的用例都被归类为“控制异常”。控制异常本质上是实现级别的正常异常:它们涉及非本地控制转移。它们在语言级别上是不同的,因为如果您的emittakewarnnextlast等由于捕获块和默认值吞没了控件异常而停止工作,那么使用Perl 6将相当尴尬!

然而,它也有点“照我说的做,而不是照我做的做”:虽然Perl 6很乐意使用异常系统来实现非本地流控制,但它在某种程度上把它隔离在语言的一个尘土飞扬的角落里,而不是把它举起来作为要做某事的例子。有充分的理由:通常,使用异常进行流控制的代码很难遵循,对于可恢复的异常来说,这种情况会加倍严重。另一个大的风险是,这样的异常可能会被使用裸try或带有默认CATCH的代码所吞噬——这使得在更大的代码库中做这件事变得相当脆弱。

我可以想象,可恢复异常的最佳用途将成为用户根本不会考虑异常的实现策略——就像takeemit一样(大多数情况下,warn)。而且,与现有的可恢复异常示例一样,正在恢复的对象将是一种异常类型,专门设计用于在可恢复情况下抛出,并且仅在合理的情况下使用。然而,在Perl6提供了一种定义定义控件异常的方法之前,我不太愿意这样做;try/default吞咽问题让它太脆弱了。

 类似资料:
  • 我已经用Java编写代码一段时间了。但有时,我不知道什么时候应该抛出异常,什么时候应该捕获异常。我正在做一个有很多方法的项目。层次结构是这样的- 所以目前我正在做的是-我在所有方法中抛出异常并在方法A中捕获它,然后将其记录为错误。 但我不确定这是否是正确的方法?或者我应该开始在所有方法中捕获异常。这就是为什么这种混乱始于我的 - 我什么时候应该抓住异常与何时应该抛出异常。我知道这是一个愚蠢的问题,

  • 我们应该在什么时候选择抛出一个异常? 我们可以在try catch中捕获此异常。 在哪种情况下,我们选择使用投掷而不是立即接球?是否与设计模式相关?

  • 问题内容: 最近,我接受了公司的采访,他们给了我一个编码问题。我得到了与纸牌有关的程序,其中一种方法是将纸牌洗牌。因此,我将该程序编写为: 在上面的代码中,我引发了我最怀疑的 IllegalArgumentException 。在什么情况下实际上应该抛出运行时异常?我们是否应该实际抛出运行时异常? 谢谢 问题答案: 我们是否应该实际抛出运行时异常? 是的,我们应该。运行时异常有特定的用途-它们发出

  • 问题内容: 我使用类只有很短的时间,编写方法时,我使所有变量都引用了self,例如self.foo。 但是,我在浏览《 wxPython in Action》 一书时发现,“ self”并没有一直使用。例如: 下面的一个确实使用“自我”。 如果我没记错的话,“自我”是指该类的特定实例,那么什么时候没有必要?有一般的经验法则吗? 问题答案: 您用于引用当前实例的属性。 您用于引用父类的方法。 如果仅

  • 谷歌正在通过电子邮件通知Android位置权限的更改: 我们将于2016年10月15日进行更改,这将影响针对API版本21(Android 5.0、Lollipop)或更高版本的应用程序,这些应用程序使用ACCESS_FINE_LOCATION但没有明确具有“android.hardware.location.gps”用途功能。展望未来,这些应用程序将可安装在没有GPS硬件的设备上。在大多数情况下

  • 首先,我想说我读过预编译头文件,我知道这是一种优化,可以节省我在每次编译时反复编译头文件的时间。 我在看助推器的留档,我在说明中看到他们说: 在配置属性中 然后他们解释道: 将Boost与预编译头一起使用没有问题;这些说明只是避免预编译头,因为它需要对示例中使用的源代码进行特定于 Visual Studio 的更改。 有人能解释一下我用黑体标出的句子吗?他们正在谈论哪些特定于视觉工作室的变化?(以