选项

如果命名值或变量可能不存在实际值,则使用 F# 中的选项类型。 选项具有基础类型,可以保存该类型的值,或者它可能没有值。

言论

以下代码演示生成选项类型的函数。

let keepIfPositive (a: int) = if a > 0 then Some(a) else None

可以看到,如果输入 a 大于 0,则生成 Some(a)。 否则,会生成 None。

当选项没有实际值时,将使用值 None。 否则,表达式 Some( ... ) 为选项指定一个值。 Some 和 None 的值在模式匹配方面非常有用,如以下函数 exists,如果选项具有值,则返回 true,如果选项没有值,则返回 false。

let exists (x: int option) =
    match x with
    | Some(x) -> true
    | None -> false

使用选项

搜索不返回匹配结果时,通常使用选项,如以下代码所示。

let rec tryFindMatch pred list =
    match list with
    | head :: tail -> if pred (head) then Some(head) else tryFindMatch pred tail
    | [] -> None

// result1 is Some 100 and its type is int option.
let result1 = tryFindMatch (fun elem -> elem = 100) [ 200; 100; 50; 25 ]

// result2 is None and its type is int option.
let result2 = tryFindMatch (fun elem -> elem = 26) [ 200; 100; 50; 25 ]

在前面的代码中,以递归方式搜索列表。 函数 tryFindMatch 采用谓词函数 pred,该函数返回布尔值和要搜索的列表。 如果找到满足谓词的元素,则递归结束,函数在表达式 Some(head)中返回值作为选项。 当空列表匹配时,递归结束。 此时找不到值 head,并返回 None。

许多 F# 库函数在集合中搜索可能或可能不存在的值都会返回 option 类型。 按照约定,这些函数以 try 前缀开头,例如 Seq.tryFindIndex。

如果值可能不存在,则选项也很有用,例如,尝试构造值时可能会引发异常。 下面的代码示例对此进行了说明。

open System.IO

let openFile filename =
    try
        let file = File.Open(filename, FileMode.Create)
        Some(file)
    with ex ->
        eprintf "An exception occurred with message %s" ex.Message
        None

上一示例中的 openFile 函数具有类型 string -> File option,因为它在文件成功打开时返回 File 对象,并在发生异常时 None。 根据具体情况,捕获异常而非允许其传播可能并不是一个合适的设计选择。

此外,仍然可以将 null 或 NULL 值传递给选项的 Some 情况。 这通常是要避免的,通常处于例程 F# 编程中,但由于 .NET 中的引用类型的性质,这有可能。

选项属性和方法

选项类型支持以下属性和方法。

属性或方法 类型 描述
None 'T option 创建具有 None 值的选项值的静态成员。
IsNone bool 如果选项具有 true 值,则返回 None。
IsSome bool 如果选项具有不 true的值,则返回 None 。
Some 'T option 一个静态成员,用于创建一个选项,其值不是 None。
值 'T 返回基础值,如果值为 System.NullReferenceException,则抛出 None。

Option 模块

有一个模块(Option)包含对选项执行操作的有用函数。 某些函数重复属性的功能,但在需要函数的上下文中非常有用。 Option.isSome 和 Option.isNone 都是测试选项是否保留值的模块函数。 Option.get 用于获取值(如果存在)。 如果没有值,则会引发 System.ArgumentException。

如果存在值,则 Option.bind 函数对值执行函数。 该函数必须恰好采用一个参数,其参数类型必须是选项类型。 函数的返回值是另一种选项类型。

选项模块还包括对应于可用于列表、数组、序列和其他集合类型的函数的函数。 这些函数包括 Option.map、Option.iter、Option.forall、Option.exists、Option.foldBack、Option.fold和 Option.count。 这些函数允许使用选项,例如零个或一个元素的集合。 有关详细信息和示例,请参阅 列表中集合函数的讨论。

转换为其他类型

选项可以转换为列表或数组。 当选项转换为其中任一数据结构时,生成的数据结构包含零个或一个元素。 若要将选项转换为数组,请使用 Option.toArray。 若要将选项转换为列表,请使用 Option.toList。

通过提供默认值来转换选项

除了转换为列表和数组之外,还可以使用 Option.defaultValue 函数提供默认值,从而将选项转换为其他类型的选项。 当您想要确保该值不是 None时,这特别有用。 例如:

let optionString = Some("F#")
let defaultString = optionString |> Option.defaultValue ""
// defaultString is "F#"

let optionInt = None
let defaultInt = optionInt |> Option.defaultValue 0
// defaultInt is 0

使用 Option.defaultValue 函数可以无缝处理 Some 和 None 事例,而无需模式匹配。

另请参阅