在那个问题中,我正在处理一些看似愚蠢或更好的东西,因为我正在使用该功能而不是解决问题.
记录中使用警告作为特殊类型的异常(“控制异常”),您可以在其中获取消息,如果您愿意可以捕获它,但也可以忽略它,它将自行恢复(尽管我对此非常愚蠢)在Where should I catch a Perl 6 warning control exception?).
除此之外,我正在考虑调用者可以处理被调用者范围之外的失败的事情.例如,重新连接到数据库,修复丢失的目录以及被调用者不负责的其他外部资源问题.
在阅读其他语言中的这类事情时,建议主要是不使用它们,因为在“真实世界”编程中,人们往往不会真正处理问题.
C# exception handler resume next的答案似乎说这是糟糕的做法和丑陋的代码.我当然还没有找到一种方法来隐藏被调用者中的一堆代码.
我修改了这个例子,虽然我不相信这是一个很好的方法,或者向初学者推荐一些东西.程序启动时会查找PID文件.如果找到一个,则会抛出异常.处理该异常会检查另一个实例是否仍在运行,这可能会引发不同类型的异常.并且,有一个处理文件IO问题.诀窍是X :: MyProgram :: FoundSemaphore可以恢复,如果其他程序没有运行(但保留其PID文件).
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; }
解决方法
我怀疑最后一个 – 警告 – 是典型的Perl 6用户唯一感兴趣的案例.捕获警告并将其发送到其他地方 – 可能是日志文件或日志服务器 – 是一件非常合理的事情.就学习Perl 6而言,这可能是可恢复异常的一个明显有用的例子.
我认为在Perl 6中利用可恢复异常的所有用例结果都被归类为“控制异常”,这一点很重要.控制异常在实现级别基本上是正常的异常:它们涉及非本地控制转移.它们在语言级别上是不同的,因为如果你的发射,接收,警告,下一个,最后一个等等停止工作,使用Perl 6会相当尴尬,因为CATCH块具有默认吞下控制异常!
然而,它也有点“像我说的那样,而不是像我一样”:虽然Perl 6很乐意使用异常系统来实现非本地流量控制,但它在语言的尘土飞扬的角落里却有点过时了.而不是把它作为一个事情的例子.并且有充分的理由:通常,使用异常来执行流控制的代码很难遵循,并且对于可恢复的异常而言,这会增加一倍.另一个很大的风险是,这些异常可能会被使用裸尝试的代码或带有默认值的CATCH所吞噬 – 这使得它在更大的代码库中变得相当脆弱.
我认为可恢复异常的最佳用途将转变为用户根本不会考虑异常的事情的实现策略 – 就像take和emit一样(并且,大多数情况下)时间,警告).并且,与现有的可恢复异常示例一样,正在恢复的内容将是一种异常类型,专门设计用于在可恢复的情况下抛出,并且仅在需要做的事情中使用.然而,在Perl 6提供了一种定义自定义控制异常的方法之前,我不太愿意这样做;尝试/默认吞咽问题使它太脆弱了.