何时在 F# 中引发 nullArg

When to raise a nullArg in F#

Exceptions (Syntax for throwing and catching) 开始,它说 F# 中内置了四个有用的异常关键字,nullArg 抛出一个 NullArgumentException:

let f x =
   if x then "ok"
   else nullArg "paramName" "message"

如果我编写的模块仅供 F# 使用,我应该什么时候提出 NullArgumentException

你不应该。例外是废话。避开他们。仅在与期望您抛出异常或不提供其他方式报告错误的外部代码交互时使用它们。

相反,如果您编写的函数可能会失败,请将其设为 return 一个 "either/or" 值 - 结果或错误。按照这些思路:

type Result<'t, 'e> = Ok of 't | Error of 'e

let f x =
   if x then Ok "ok"
   else Error "boo!"

这样,调用代码就无法 "forget" 处理错误情况:编译器不允许。这是一件好事。

顺便说一句,F# 4.1 includes the Result type in the box(和一些有用的实用程序)。查看 post.

中的示例

还感兴趣:here's 关于该主题的一系列精彩文章和演示视频。

即使您编写代码只是为了使用 F#,我认为在 F# 代码中使用异常也有完全有效的情况。

如果您有预期的错误,那么最好使用 Result 类型。这包括读取可能格式错误的数据(因为它来自用户)或验证可能不正确的用户输入。

但是,我认为异常对于指示 异常 情况仍然有用。具体来说,对于 nullArg,您需要它的情况并不多,因为 F# 主要消除了 null 值,但是当您将 .NET 类型作为参数时,您仍然可以获得一个值。如果你有一个接受 IDictionary<string, string> 的函数,而你从没想过它会是 null,这样写可能会有用:

let lookupName (dict:IDictionary<string, string>) = 
  if dict = null then nullArg "dict" "lookupName expects a valid dictionary!"
  if dict.ContainsKey "name" then dict.["name"] else "anonymous"

由于 IDictionary 是 .NET 类型,F# 无法确保它永远不会 null 并且显式处理这种情况可能会给您提供更有用的错误信息,以防您不小心做错了什么在你的代码中。