选项
如果命名值或变量可能不存在实际值,则使用 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 |
如果选项具有 None 值,则返回 true 。 |
IsSome | bool |
如果选项具有不 None 的值,则返回 true 。 |
Some |
'T option |
一个静态成员,用于创建一个选项,其值不是 None 。 |
值 | 'T |
返回基础值,如果值为 None ,则抛出 System.NullReferenceException 。 |
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
事例,而无需模式匹配。