5.3.2.1 用 F# 匹配差别联合
当使用差别联合时,必须要处理所有可能的选项,因为,我们不知道这个值到底表示哪一个选项。回忆一下以前类似的情况,处理列表时,问题要检查列表是否为空,我们是使用模式匹配实现的:match 构造能够根据几种模式检查值。我们可以用同样的功能,处理差别联合,只是这里模式换成了识别器。清单 5.5 是获取计划事件下一次发生时间的示例。
清单 5.5 计算事件的下一次发生 (F#)
let getNextOccurrence(schedule) =
matchschedule with
|Never -> DateTime.MaxValue [1]
|Once(eventDate) –> [2]
if(eventDate > DateTime.Now) then eventDate
elseDateTime.MaxValue
|Repeatedly(startDate, interval) –> [3]
letsecondsFromFirst = (DateTime.Now - startDate).TotalSeconds
let q = secondsFromFirst /interval.TotalSeconds | [4]
letq = max q 0.0 |
startDate.AddSeconds
(interval.TotalSeconds * (Math.Floor(q) + 1.0))
这个示例是有点复杂,但它展示了F# 程序的典型结构。我们使用标准 .NET DateTime 和 TimeSpan 结构处理日期和时间;使用模式匹配检查已经选择了哪一个计划。第一种情况[1],返回 DateTime.MaxValue,这是一个特殊值,用来表示事件在未来所有日期都没有计划;第二种情况[2],如果事件还没有发生,则返回事件日期;最后一种情况(重复事件)更复杂[3],我们首先计算过去已经发生了多少次事件,返回下一次发生的时间。可以看到,我们在代码中两次声明 q 值[4],这称为隐藏值(hiding a value),如果我们想把复杂的计算拆成两个或更多个步骤,这是很有用的,可以确保我们不会意外地使用中间值。
可以发现,用于检查值是否值匹配特定的识别器的模式,与我们在前面用于构造值的模式完全相同;模式也提取保存的值作为参数值,指定给新的值(分别是 eventDate 和带 interval 的 startDate),这样,我们就可以立即使用它们。