5.3.4 F# 中的选项(option)类型

728 篇文章 1 订阅
349 篇文章 0 订阅

5.3.4 F# 中的选项(option)类型

 

我们常常需要表达这样的思想,某些计算可能会返回未定义的值;在 C# 中,通常用返回 null(空值)实现。不幸的是,使用 null 频繁导致错误:写代码,可能会轻易地假定方法不返回空,一旦这个假设不成立,就会看到NullReference 错误。当然,好代码总是在适当的地方检查值是否为空,为应用程序写的单元测试,大量的检查就是验证这种特定情况下的行为。

F# 使空值的使用最小化,通常只在与 .NET 类型进行互操作的情况下才使用。为了表示可能返回未定义结果的计算,我们使用选项(option)类型。当函数以 option 作为返回类型时,显式声明,结果可能是未定义的;同时,编译器强制调用程序处理未定义的结果。

选项类型是有两个可选值的差别联合,识别器 Some 用于创建有值的选项;None 用于表示未定义的值。清单 5.7 中的函数,从控制台读取输入,当用户没有输入数字时,返回未定义的值。

 

清单 5.7 读输入作为可选值 (F# Interactive)

> open System;;

> let readInput() =

   lets = Console.ReadLine()

   matchInt32.TryParse(s) with  <-- 尝试解析输入

   |true, parsed -> Some(parsed)

   |_ -> None

;;

val readInput : unit -> int option

 

代码相当简单:读取输入,使用 TryParse 方法解析,用选项类型中的一种情况构造返回值。我们使用模式匹配中一个有趣和强大的功能来实现这个函数;match 构造的输入是从 TryParse 方法返回的元组。当解析成功,元组的第一个值为真,第二个值就是我们感兴趣的数值。要处理模式匹配内部的这种情况,我们指定第一个模式为常量 true,第二个模式为新建的值 parsed。当元组中第一个元素为真时,模式匹配把解析后的数字指定给值 parsed,使用 Some 返回这个结果。

第二个分支使用下划线模式来处理所有剩余的情况。在这种情况下,我们知道解析已经失败,所以,使用 None 返回未定义的结果。我们还可以 F# Interactive 看到输出的方法签名,返回 int option,就是说,option 类型是泛型,在这里,具有整型值。我们会在第 5.4.2 节看到如何定义这样的泛型类型。

现在,我们先看一下使用这个函数的代码。这里,我们看到使用选项类型的真正好处,语言会强制我们写处理未定义值的代码,因为访问值的唯一方法是使用模式匹配。可以在清单 5.8 中看到这个示例。

 

清单 5.8 处理使用选项类型的输入 (F# Interactive)

> let testInput() =

   letinput = readInput()  [1]

   matchinput with      [2]

   |Some(number) –>    <-- 包含正确的输入

     printfn"You entered: %d" number

   |None –>            <-- 包含未定义的输入

     printfn"Incorrect input!";;

val testInput : unit –> unit

 

> testInput();;   | 检查第一种情况

42            |

You entered: 42  |

 

> testInput();;   | 检查第二种情况

fortytwo       |

Incorrect input!  |

 

可以发现,我们不能在调用 readInput 函数[1]后直接使用这个值,这是关键的区别,它使程序更安全,因为当函数返回空值时,不必检查这种可能性。要在 F# 中读取这个值,必须使用模式匹配[2],我们为每个选项类型情况写了一个分支。我们已经知道,F# 会验证模式匹配是否完整,即,是否涵盖了所有可能的选项,这就保证了我们写的代码不会意外地只包含 Some 识别器分支。清单 5.8 也遵循 F# 的最佳做法,通过在 F # Interactive 中立刻测试代码,检查它的行为在两种情况下都正确。

 

可空(Nullable)和选项类型

 

F# 的选项类型在某些方面类似于 C# 中的Nullable<T> 类型,但是,更通用、更安全。在 C# 中,当我们想要表示一个缺失值(missing value),通常使用 Null,但这只能用于引用类型。可空类型能用于创建值类型,null 也是有效值。

在 F# 中,null,不是任何在 F# 中声明的类型的有效值(尽管,对于已有的 .NET 引用类型,它仍然是有效值)。因此,一理我们需要创建可能为空的任意值时,就要把实际类型包装到选项类型中。由于有了模式匹配,编译器也能够确保我们实现的代码,始终可以处理缺失值的情况。

 

现在,我们已经知道如何使用选项类型,以及对于 F# 编程的重要性,下面,就要讨论如何实现了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值