有没有办法使用 kprintf (或类似的)对异常进行字符串格式化,并且仍然收到有关冗余参数的警告?到目前为止我有:
type MyException (s:string) =
inherit System.Exception(s)
static member Raise msg =
Printf.kprintf (fun s -> raise (MyException(s))) msg
do
MyException.Raise "boom %d" 9 1 // Gives NO warning about redundant arguments
failwithf "boom %d" 9 1 // Gives warning about redundant arguments
Run Code Online (Sandbox Code Playgroud)
我知道我可以使用新的 $ 格式,但希望与旧版本的 F# 保持兼容。
问题不是来自kprintf,而是来自raise,它允许函数的返回类型是任何类型,包括柯里化函数。该函数failwithf将此警告作为特殊情况。
如果你返回,让\xe2\x80\x99s,一个字符串或一个单位,你实际上会得到一个错误。缺点是现在你不能再在每个位置加注,因为返回参数不再是通用的。
\n您可以通过强制使用类型参数来解决这个问题,但这对于调用者来说不太理想。
\n例如,这可行,但如果将 的返回类型更改f为字符串,则会失败:
open System\ntype MyException (s:string) = \n inherit System.Exception(s)\n static member Raise msg = \n Printf.kprintf (fun s -> raise (MyException s) |> ignore) msg\n \nmodule Test =\n let f() : unit = // string won\xe2\x80\x99t work\n MyException.Raise "boom %d" 9 10 // error, as expected\nRun Code Online (Sandbox Code Playgroud)\n这是某种解决方法。您可以使用泛型类型约束来限制类型,并利用 F# 函数类型不可比较或不可等价、没有适当值的事实null。
由于 F# 强大的结构相等支持,您将使用的大多数类型都是可相等的。类型约束的其他选项包括struct(仅限结构)null(不包括记录和 DU 类型)或某个继承约束(如果适合您的用例)。
例子:
\ntype MyException (s:string) = \n inherit System.Exception(s)\n\n static member Raise<\'T when \'T : equality> msg = \n let raiser s =\n raise (MyException s)\n Unchecked.defaultof<\'T> // fool the compiler\n\n Printf.kprintf raiser msg\n \nmodule Test =\n let f() = MyException.Raise "boom %d" 9\n let g() = MyException.Raise "boom %d" 9 10 // error\nRun Code Online (Sandbox Code Playgroud)\n除了类型限制之外,缺点是您收到的错误将是类型错误,而不是您请求的警告。
\n