代码之家  ›  专栏  ›  技术社区  ›  Bruno Reis

f异常处理构造

  •  8
  • Bruno Reis  · 技术社区  · 15 年前

    为什么F不自然地支持Try/With/Finally块?

    这不合理吗 尝试 某物, 处理 不管它抛出了什么异常,至少要记录该异常,然后 务必 一些代码在这之后执行?

    当然,我们可以

    try
        try
            ...
        with ex -> ...
    finally
        ...
    

    但这似乎太人为了,它清楚地表明“F反对尝试/使用/最终”。为什么会这样?

    5 回复  |  直到 12 年前
        1
  •  12
  •   Tomas Petricek    15 年前

    正如前面提到的,你通常会使用 try-with-finally 以确保在发生异常时正确释放所有资源。我认为在大多数情况下,使用 use 关键词:

    let input = 
      try
        use stream = new FileStream("C:\temp\test.txt");
        use rdr = new StreamReader(stream);
        Some(rdr.ReadToEnd())
      with :? IOException as e -> 
        logError(e)
        None
    

    我想这就是你不需要的原因 最后试试看 像你用其他语言一样频繁。但是,当然,在某些情况下,您可能需要它(但是您当然可以通过创建 IDisposable 使用 对象表达式 (这在语法上非常容易)。但我认为这是如此罕见,以至于F团队不需要担心这一点。

        2
  •  6
  •   Brian    15 年前

    正交性?正如您所展示的,您可以简单地将一次尝试嵌套在一次尝试中。(我想这就是IL级别的情况。)

    也就是说,在未来的语言版本中,我们可能会考虑使用finally。

    就我个人而言,我只需要几次,但当你确实需要它时,需要做额外的嵌套/缩进有点麻烦。一般来说,我发现我很少编写异常处理代码,通常只是一个或另一个(例如,最终恢复不变或其他事务语义,或在应用程序顶部附近“catch”记录异常或显示用户诊断)。

    但是我认为对于语言设计来说没有太多的东西需要“阅读”。

        3
  •  2
  •   Guy Coder    12 年前

    因为伟大的细节在

    Expert .NET 2.0 IL Assembler Serge Lidin

    参见:第14章,托管异常处理

    最后 过错 处理程序不能与其他处理程序和平共存,因此如果一个受保护的块具有 最后 过错 处理程序,它不能有任何其他内容。结合一 最后 过错 处理程序与其他处理程序一起,您需要将受保护的和处理程序块嵌套在其他受保护的块中,…,以便每个 最后 过错 处理程序有自己的个人保护块。”

    第300页

    尝试/捕获使用 过错 处理程序和try/finally使用 最后 处理程序。

    见: ILGenerator.BeginFaultBlock Method

    如果你发射一个 过错 异常块中还包含 捕捉处理程序或 最后 处理程序, 结果代码是 不可验证的 .

    因此,所有的.NET语言都可以考虑使用句法surgar,因为f_是如此的新,所以它们还没有实现它。没有伤害,没有犯规。

        4
  •  1
  •   Pascal Cuoq    15 年前

    我将在回答中澄清我的意见。

    1. 我坚持有 没有理由假定您希望捕获异常并在同一级别完成一些资源 . 也许你已经习惯了用一种同时处理两种语言是很方便的语言来做这件事,但这是巧合。当您没有从内部块捕获所有异常时,定案很方便。 try...with 用于捕获异常,以便正常继续计算。这两者之间根本没有关系(如果有什么关系的话,它们会朝相反的方向发展:你是抓住了例外,还是让它过去?).

    2. 你为什么要最终决定什么? GC不应该为您管理未引用的资源吗?啊…但是,该语言试图让您访问使用副作用、显式分配和取消分配的系统原语。您必须取消分配已分配的内容(在所有情况下)…难道你不应该责怪系统提供的腐朽接口,而不是F,在这种情况下,F只是信使吗?

        5
  •  0
  •   Dario    15 年前

    但这似乎太人为了,它清楚地表明“F反对尝试/使用/最终”。为什么?

    我想F可能是“反对”异常处理的。为了.NET的互操作性,它必须支持它们,但基本上, 函数编程中没有异常处理*。 .

    抛出/捕获异常意味着执行甚至没有被类型系统注意到的“无处跳转”,这两种类型系统都从根本上违背了功能哲学。

    可以使用纯函数(单元)代码来包装异常。所有错误都是通过值处理的,根据基础类型系统,并且没有跳跃/副作用。

    而不是编写函数

    let readNumber() : int = ...
    

    这可能会引发任意的异常,您只需声明

    let readNumber() : int option = ...
    

    这使得这一点通过其类型签名自动清除。

    *这并不意味着我们不处理异常情况,它只是关于.NET/C++中异常处理的一种。