我有一个实用程序函数,它将记录错误消息(包括字符串格式)与引发异常(raise
现有异常或failwith
使用格式化的错误消息调用,类似于下面的 logAndFailWithf 函数(尽管实际上它使用日志框架,不写入文本文件):
let logAndFailWithf exOpt =
let logFile = new StreamWriter("log.txt")
Printf.ksprintf <| fun message ->
try match exOpt with
| Some ex ->
logFile.WriteLine("{0}\r\n{1}", message, ex)
raise <| Exception(message, ex)
| None ->
logFile.WriteLine(message)
failwith message
finally logFile.Close()
val logAndFailWithf : exOpt:#exn option -> (Printf.StringFormat<'b,'c> -> 'b)
如果直接调用此函数,则可以正常工作,如以下简单示例所示:
let s = "123x"
let x = try Int32.Parse s
with | ex -> logAndFailWithf (Some ex) "Failed to parse string s: %s" s
System.Exception: Failed to parse string s: "123x" --->
System.FormatException: Input string was not in a correct format.
at System.Number.StringToNumber(String str, NumberStyles options,
NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
然而,在现实世界的场景中,日志函数被传递给另一个函数,当它遇到异常时使用它来记录和抛出异常,类似于以下内容:
let exmaple param1 param2 (log: exn option -> Printf.StringFormat<_,_> -> _) =
let x = try Int32.Parse param1
with | ex -> log (Some ex) "Failed to parse param1: \"%s\"" param1
let y = try Int64.Parse param2
with | ex -> log (Some ex) "Failed to parse param2: \"%s\"" param2
printfn "Successfully Parsed Parameters: param1 = %d; param2 = %d" x y
在这种情况下,编译器会在第二个 let 绑定 ( ) 上报告错误,let y = ...
并显示以下消息:
error FS0001: This expression was expected to have type
'int64'
but here has type
'int'
这似乎发生在与 log 函数的第一次使用不具有相同类型的表达式中任何 log 函数的使用(在上面的示例中,int64
when bindingy
而不是int
when binding x
),我无法找到一种表达log
参数类型的方法,该方法既与函数的签名相匹配,logAndFailWithf
又在同一函数中用于不同类型的表达式时起作用。
如何将此隐式泛型函数作为参数传递给其他函数,以便可以在不同类型的表达式中调用它?