【问题标题】:CATCH and throw in custom exception捕获并抛出自定义异常
【发布时间】:2023-03-18 22:35:01
【问题描述】:

应该在“throw”之后严格调用“CATCH”吗?

示例 1:

say 'Hello World!';

class E is Exception { method message() { "Just stop already!" } }

CATCH {
    when E {
            .resume;
    }
}

E.new.throw;

错误:

找不到方法“sink”:没有方法缓存,也没有 .^find_method in 在 /tmp/739536251/main.pl6 第 11 行阻止

示例 2:

say 'Hello World!';

class E is Exception { method message() { "Just stop already!" } }

E.new.throw;

CATCH {
    when E {
            .resume;
    }
}

没有错误

【问题讨论】:

    标签: raku


    【解决方案1】:

    我是an already filed .resume bug。


    错误消息不是 P6 产生的最棒的消息,但从技术上讲它不是 LTA,因为它是描述性的并且与错误相关(由错误引起)。


    捕获并抛出自定义异常

    我认为这只是一个 .resume 错误,而不是关于自定义异常。

    应该在“throw”之后严格调用“CATCH”吗?

    不,这不是问题。 (也就是说,把它放在.throw 之后恰好可以避免这个错误;我稍后再讨论。)


    在蓬勃发展的代码中,你抛出一个异常,然后.resume 来响应它。根据文档.resume:

    在.throw 离开的地方恢复控制流

    在这种情况下表示箭头指向的位置:

    E.new.throw ;
               ?
    

    现在,考虑这个程序:

    42;
    

    如果你运行那个程序,你会看到:

    Useless use of constant integer 42 in sink context (line 1)
    

    这是因为 Raku 在决定语句末尾的操作时应用了"sink context" 规则。应用接收器上下文需要对语句产生的值调用.sink。对于42,.sink 方法会生成“无用”警告。

    但是.resumed 抛出的异常的价值是什么?

    class E is Exception {}
    CATCH { when E { .resume } }
    say E.new.throw.^name; # BOOTException
    E.new.throw.sink;      # Cannot find method 'sink':
                           # no method cache and no .^find_method
    

    原来它是一个BOOTException 对象,它不是一个高级 Raku 对象,而是一个低级 VM 对象,一个没有 .sink 方法的对象(并且还阻碍了 P6 查找方法,因此出现“我尝试了一切”错误消息)。


    那么为什么将 CATCH 块放在 之后会有所不同?

    似乎只有在 throw 语句是 last 语句时才会出现该错误。这工作正常,只显示42:

    class E is Exception {}
    CATCH { when E { .resume } }
    E.new.throw;
    say 42;
    

    您大概知道,Raku 对块的最后一条语句进行了特殊处理。也许这个错误与此有关。

    【讨论】:

      【解决方案2】:

      CATCH 必须在同一块中。

      第一个示例中的问题是没有E,而是抛出了另一个异常。试试

      class E is Exception { method message() { "Just stop already!" } };
      
      CATCH {
          when E {
              .resume;
          }
          default { say .perl }
      }
      
      E.new.throw;
      

      您可以更改 when 块

      class E is Exception { method message() { "Just stop already!" } };
      
      CATCH {
          when E {
              say .message;
          }
      }
      
      E.new.throw;
      

      或类E的定义,例如

      class E is Exception { 
          has $.resume; 
          method message() { "Just stop already!" } 
      };
      
      CATCH {
          when E {
              say .resume;
          }
      }
      
      E.new(resume => 'stop here').throw;
      

      【讨论】:

      • 好的,信息(“没有方法(属性)简历。”)具有误导性。我已将其从答案中删除。
      猜你喜欢
      • 2015-07-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-08
      • 1970-01-01
      相关资源
      最近更新 更多