我一直在尝试编写一个执行以下逻辑的Perl 6表达式:计算子表达式并返回其值,但如果这样做会导致引发异常,请捕获异常并返回固定值.
例如,假设我想要分割两个数字,并且-1如果发生错误,则将表达式求值为.在Ruby中我可能会写:
quotient = begin; a / b; rescue; -1; end
Run Code Online (Sandbox Code Playgroud)
在Emacs Lisp中可能写成:
(setq quotient (condition-case nil (/ a b) (error -1))
Run Code Online (Sandbox Code Playgroud)
我的第一次Perl 6尝试是这样的:
sub might-throw($a, $b) { die "Zero" if $b == 0; $a / $b }
my $quotient = do { might-throw($a, $b); CATCH { default { -1 } } };
Run Code Online (Sandbox Code Playgroud)
但$quotient无论是否$b为零,这里最终都是未定义的.
似乎CATCH忽略了返回的值,或者至少在描述异常如何工作的doc页面上,所有CATCH主体仅执行具有副作用的事情,例如日志记录.
该页面提到try了另一种选择.我可以写一些例子:
my $quotient = try { might-throw($a, $b) } // …Run Code Online (Sandbox Code Playgroud) 也许我真正的问题是"这是一个适合学习Perl 6的功能 "吗?基于此Perl 6 CATCH块是否能够更改词法范围中的变量?,似乎最简单的例子可能超出了一个简单的例子.
在那个问题中,我正在处理一些看似愚蠢或更好的事情,因为我正在使用该功能而不是解决问题.
有记录的使用警告作为特殊类型的异常("控制异常"),你得到消息,如果你愿意可以捕获它,但也可以忽略它,它将自行恢复(虽然我对此相当愚蠢在哪里我应该捕获Perl 6警告控制异常?).
除此之外,我正在考虑调用者可以处理被调用者范围之外的失败的事情.例如,重新连接到数据库,修复丢失的目录以及被调用者不负责的其他外部资源问题.
在阅读其他语言中的这类内容时,建议主要是不使用它们,因为在"真实世界"编程中,人们往往不会真正处理问题.
C#异常处理程序恢复的答案似乎说它是糟糕的做法和丑陋的代码.我当然还没有找到一种方法来隐藏被调用者中的一堆代码.
我修改了这个例子,虽然我不相信这是一个很好的方法,或者向初学者推荐一些东西.程序启动时会查找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 …Run Code Online (Sandbox Code Playgroud) “ CATCH”是否应该在“ throw”之后严格调用?
范例1:
say 'Hello World!';
class E is Exception { method message() { "Just stop already!" } }
CATCH {
when E {
.resume;
}
}
E.new.throw;
Run Code Online (Sandbox Code Playgroud)
错误:
找不到方法“接收器”:在/tmp/739536251/main.pl6第11行的块中没有方法缓存,也没有。^ find_method
范例2:
say 'Hello World!';
class E is Exception { method message() { "Just stop already!" } }
E.new.throw;
CATCH {
when E {
.resume;
}
}
Run Code Online (Sandbox Code Playgroud)
没错
目前(截至 2020 年 8 月)Rakudo 不会在编译时对函数的返回值进行类型检查;也就是说,它不提供函数满足其返回约束的静态保证。具体来说,以下两个函数都编译为 Raku:
sub get-int(--> Int) { 'bug' }
Run Code Online (Sandbox Code Playgroud)
sub get-int($a --> Int) {
when $a == 5 { 'Rare bug' }
default { 42 }
}
Run Code Online (Sandbox Code Playgroud)
我有两个相关的问题:
有没有办法知道当前在编译时发生了什么(如果有)类型检查?(通过某人编写的列表,文档中的某处,或 Rakudo 源中的中心位置)还是比这更临时?
缺乏编译时类型检查是否是有意的设计决策?或者正在添加更多静态类型检查的东西,有一天会很高兴,但还没有实现?
(我熟悉 Johnathan 对Raku 中类型/约束的性能惩罚?的精彩回答,其中指出“Raku 要求写入程序的类型约束最迟在运行时强制执行。”该答案描述了避免运行的各种方法- 类型检查的时间成本,但没有描述在编译时完成的类型检查(如果有的话)(这肯定会避免运行时成本!)。
我正在玩可恢复的例外.在这个例子中,我尝试编号不编号的东西.我抓住了它并尝试给$value变量一个合适的值然后恢复执行:
try {
my $m = 'Hello';
my $value;
$value = +$m;
put "Outside value is ?{$value.^name}?";
CATCH {
when X::Str::Numeric {
put "?$m? isn't a number!";
put "Inside value is ?{$value.^name}?";
$value = 0;
put "Inside value is now ?$value.?";
.resume;
}
default {
put "Unhandled type ?{.^name}?";
}
}
put "End of the block";
}
put "Got to the end.";
Run Code Online (Sandbox Code Playgroud)
该CATCH块可以看到它所处的词法范围,一个恢复从它停止的地方开始.我希望我能够更改$value并让其余的块使用该值,但在CATCH该值之外变为失败:
?Hello? isn't a number!
Inside value is ?Any?
Inside …Run Code Online (Sandbox Code Playgroud)