如何创建新的语法块以便最后尝试?

时间:2012-04-03 10:59:56

标签: syntax exception-handling f#

我经常使用:

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

我在这里看到的问题是

  • 非常见语法,在mytry中没有尝试使用finally关键字,只需&lt; | &LT; | &LT; |对于每一个,但我认为这是一个较小的麻烦
  • with:我不知道怎么才能意识到这一部分。如果我能意识到它会是什么样子......

2 个答案:

答案 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的观点,在大多数情况下,你应该对usetry .. with没问题。