我经常使用:
try
try
with
finally
所以我很有意思,如果有可能使新语法运算符不写“尝试”两次。
let mytry foo bar foobar =
try
try
foo
with
| _ -> bar // weird part here, I want to have a match
finally foobar
mytry
<| foo
<| | :? SocketException ->
| _ -> // ok it looks funny but how to realize it?
<| foobar
我在这里看到的问题是
答案 0 :(得分:2)
问题是你是否真的需要try/finally
。大多数时候try/finally
用于处理资源,即使发生异常也是如此。但您始终可以使用use
关键字替换它。
例如:
open System.IO
let openFile(url: string) =
let fileStream = File.OpenText(url)
try
try
let readline = fileStream.ReadLine()
printfn "Readline: %s" readline
with
| :? IOException as ex ->
printfn "IOException: %A" ex
| ex -> printfn "Another exception: %A" ex
finally
fileStream.Dispose()
可以改写为:
let openFile(url: string) =
use fileStream = File.OpenText(url)
try
let readline = fileStream.ReadLine()
printfn "Readline: %s" readline
with
| :? IOException as ex ->
printfn "IOException: %A" ex
| ex -> printfn "Another exception: %A" ex
出于学习目的,您可以使用高阶函数定义mytry
,如下所示:
let mytry foo bar foobar =
try
try
foo ()
with
| exn -> bar exn
finally foobar ()
但在上面的例子中看起来并不是很好:
let myOpenFile(url: string) =
let fileStream = File.OpenText(url)
mytry (fun () -> let readline = fileStream.ReadLine()
printfn "Readline: %s" readline)
(fun ex -> match ex with
| :? IOException ->
printfn "IOException: %A" ex
| _ -> printfn "Another exception: %A" ex)
(fun () -> fileStream.Dispose())
答案 1 :(得分:2)
您可以编写一个高阶函数,将这三个部分作为单独的函数。 try
的正文将是一个函数unit -> 'R
,其中'R
就是结果。异常处理程序只需处理一些异常,因此您可以返回option
来说明您是否处理了结果,或者是否希望重新抛出异常。处理程序的类型为exn -> 'R option
。然后,终结器只是一个函数unit -> unit
。
使用方法并不像使用内置语言功能那样优雅,但它可以解决问题:
tryWithFinally
(fun () ->
1/0 ) // The nested body
(function
| :? DivideByZeroException -> Some -1 // Handle division by zero
| _ -> None ) // Rethrow any other exceptions
(fun () ->
printfn "done" )
一旦你知道结构,实现就很容易,但为了完整性,这里是:
let tryWithFinally f handler finalizer =
try
try f()
with e ->
match handler e with
| Some r -> r
| None -> reraise()
finally
finalizer()
无论如何,我同意@pad的观点,在大多数情况下,你应该对use
和try .. with
没问题。