为什么F#自然不支持try / with / finally块?
尝试某些事情是否有意义,处理与它抛出的任何异常,至少记录异常,然后确保有些代码会在所有代码之后执行吗?
当然,我们可以做到
try
try
...
with ex -> ...
finally
...
但这似乎过于人为,它清楚地表明“F#反对try / with / finally”。那是为什么?
答案 0 :(得分:12)
正如有人已经提到的那样,您通常会使用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
我认为这主要是您不像其他语言那样经常需要try-with-finally
的原因。但是当然,在某些情况下你可能需要它(但你可以通过使用对象表达式创建IDisposable
的实例来避免这种情况(这在语法上非常简单)。但是我认为这是非常罕见的,F#团队并不需要担心这一点。
答案 1 :(得分:6)
正交?你可以简单地在try-finally中嵌套try-with,如你所示。 (无论如何,这是在IL级别发生的事情,我想。)
也就是说,试试看终结是我们在未来的语言版本中可以考虑的事情。
就我个人而言,我只想要几次,但是当你确实需要它时,必须做额外的嵌套/缩进是有点麻烦的。一般来说,我发现我很少编写异常处理代码,它通常只是一个或另一个(例如最终恢复不变或其他事务语义,或者在应用程序顶部附近的'catch'来记录异常或显示用户诊断)。
但我不认为这里有很多关于语言设计的内容。
答案 2 :(得分:2)
没有详细说明因为好的细节在
Serge Lidin的见:Ch。 14,托管异常处理
&#34; 最终和错误处理程序无法与其他处理程序和平共存,因此如果受保护的块具有最终或<强>错误处理程序,它不能有任何其他东西。要将最终或错误处理程序与其他处理程序相结合,您需要将受保护和处理程序块嵌套在其他受保护的块中,...,以便每个最终或错误处理程序有自己的个人防护块。&#34;
PG。 300
try / catch使用错误处理程序,try / finally使用 finally 处理程序。
请参阅:ILGenerator.BeginFaultBlock Method
如果在同样包含a的异常块中发出错误处理程序 catch处理程序或 finally 处理程序,生成的代码是 无法验证强>
因此,所有的.net语言都可以被认为是使用语法的语言,因为F#是如此新颖,他们还没有实现它。没有坏处。
答案 3 :(得分:1)
我将在这个答案中澄清我的评论。
我坚持认为没有理由假设您要捕获异常并在同一级别完成某些资源。也许你习惯于用一种方便的方式同时处理这两种语言,但是当它发生时它是巧合的。当你没有从内部块中捕获所有异常时,最终化很方便。 try...with
用于捕获异常,以便计算可以正常继续。两者之间根本没有任何关系(如果有的话,它们会朝着相反的方向发展:你是在捕捉异常,还是让它通过?)。
为什么要完成任何事情? GC不应该为您管理未引用的资源吗?啊......但是语言试图通过明确的分配和解除分配来访问处理副作用的系统原语。您必须取消分配已分配的内容(在所有情况下)...您不应该责怪系统提供的腐烂接口而不是F#,在这种情况下只是信使吗?
< / LI> 醇>答案 4 :(得分:0)
但这似乎过于人为,它清楚地表明“F#反对try / with / finally”。那是为什么?
我猜F#可能会“反对”异常处理。为了.NET互操作性,它必须支持它们,但基本上,在函数式编程中没有异常处理* 。
投掷/捕捉异常意味着执行“跳到无处”,类型系统甚至都没有注意到这种情况,这种根本不符合功能哲学。
您可以使用纯函数(monadic)代码来包装异常。所有错误都是通过值来处理的,就基础类型系统而言,没有跳跃/副作用。
而不是写一个函数
let readNumber() : int = ...
可能会抛出任意异常,你只需说明
let readNumber() : int option = ...
通过类型签名自动清除此点。
*这并不意味着我们不会处理特殊情况,而只是关于.NET / C ++中的异常处理。