Null 值

本主题介绍如何在 F# 中使用 null 值。

空值

在 F# 中,null 值通常不用于值或变量。 但是,在某些情况下,null 显示为异常值。 如果在 F# 中定义了类型,则不允许将 null 作为常规值,除非将 AllowNullLiteral 属性应用于该类型。 如果某个类型是用其他 .NET 语言定义的,则 null 是一个可能的值,并且当你与此类类型进行互操作时,你的 F# 代码可能会遇到 null 值。

对于在 F# 中定义并严格从 F# 中使用的类型,直接使用 F# 库创建空值的唯一方法是使用 Unchecked.defaultofArray.zeroCreate。 但是,对于从其他 .NET 语言中使用的 F# 类型,或者如果将该类型与不是用 F# 编写的 API(例如 .NET Framework)一起使用,则可能会出现 null 值。

如果可以在另一种 .NET 语言中使用具有可能为 null 值的引用变量,则可以在 F# 中使用 option 类型。 如果没有对象,则可以使用选项值 option,而不是使用 F# None 类型的 null。 如果有对象,则可将选项值 Some(obj) 用于对象 obj。 有关详细信息,请参阅选项。 请注意,如果对于 Some xx 恰好是 null,则仍然可以将 null 值打包到选项中。 因此,在值为 None 时使用 null 非常重要。

null 关键字是 F# 中的有效关键字,当使用 .NET Framework API 或使用以另一种 .NET 语言编写的其他 API 时,必须使用该关键字。 在以下两种情况下,可能需要 null 值:调用 .NET API 并将 null 值作为参数传递,以及解释 .NET 方法调用的返回值或输出参数。

若要将 null 值传递到 .NET 方法,只需在调用代码中使用 null 关键字。 下面的代码示例阐释了这一点。

open System

// Pass a null value to a .NET method.
let ParseDateTime (str: string) =
    let (success, res) =
        DateTime.TryParse(str, null, System.Globalization.DateTimeStyles.AssumeUniversal)

    if success then Some(res) else None

若要解释从 .NET 方法获取的 null 值,请尽可能使用模式匹配。 以下代码示例展示了如何使用模式匹配来解释在 ReadLine 尝试读取输入流末尾之后返回的 null 值。

// Open a file and create a stream reader.
let fileStream1 =
    try
        System.IO.File.OpenRead("TextFile1.txt")
    with :? System.IO.FileNotFoundException ->
        printfn "Error: TextFile1.txt not found."
        exit (1)

let streamReader = new System.IO.StreamReader(fileStream1)

// ProcessNextLine returns false when there is no more input;
// it returns true when there is more input.
let ProcessNextLine nextLine =
    match nextLine with
    | null -> false
    | inputString ->
        match ParseDateTime inputString with
        | Some(date) -> printfn "%s" (date.ToLocalTime().ToString())
        | None -> printfn "Failed to parse the input."

        true

// A null value returned from .NET method ReadLine when there is
// no more input.
while ProcessNextLine(streamReader.ReadLine()) do
    ()

也可通过其他方式生成 F# 类型的 null 值,例如使用 Array.zeroCreate 调用 Unchecked.defaultof。 必须谨慎处理此类代码,使 null 值保持为封装状态。 在仅用于 F# 的库中,无需在每个函数中检查 null 值。 如果要编写与其他 .net 语言进行互操作的库,则可能必须添加对 null 输入参数的检查并引发 ArgumentNullException,就像在 C# 或 Visual Basic 代码中执行的那样。

可以使用以下代码检查任意值是否为 null。

match box value with
| null -> printf "The value is null."
| _ -> printf "The value is not null."

请参阅