可区分联合类型表示固定数量的具名事例。可区分联合的每个值都恰好对应其中一个具名事例。
可区分联合使用 type 关键字定义,各个事例之间用竖线(|)分隔:
type Season =
| Spring
| Summer
| Autumn
| Winter
可区分联合的每个事例都可以选择性地关联数据,不同事例可以关联不同类型的数据。如果所有事例都没有关联数据,那么这种可区分联合就类似于其他语言通常所说的枚举(或 enum)。
type Number =
| Integer of int
| Float of float
| Invalid
要创建某个特定事例的值,可以引用它的名字(例如 Success)。由于事例名本质上就是构造函数,关联的数据可以像普通函数实参一样传入。如果另一个可区分联合定义了同名的事例,就需要使用它的完整名称(例如 Result.Success)。
let byName = Integer 2
let byFullName = Number.Invalid
可区分联合具有结构相等性,也就是说,同一事例且(可选)数据相同的两个值彼此等价。
虽然可以用 if/elif/else 表达式处理可区分联合,但推荐的做法是通过模式匹配,使用标识符模式:
let describe number =
match number with
| Integer i -> sprintf "Integer: %d" i
| Float d -> sprintf "Float: %f" d
| Invalid -> "Invalid"
这个练习里正逢情人节,你和伴侣打算一起做点有意思的事。伴侣有很多想法,现在要你给这些想法评分,好从中挑出一个活动来。
伴侣提出了以下想法:
你有六个任务,帮你选出情人节的活动。
对于伴侣提出的每个想法,你都要从三种选项中选择一个来回应:yes、no 或 maybe。
定义可区分联合Approval,用以下三个用例来表示这些选项:Yes、No 和 Maybe。
伴侣选出了两家可能去的餐厅:一家是 Korean 菜系,另一家是 Turkish 菜系。
定义可区分联合Cuisine,用以下两个用例来表示这两种菜系:Korean 和 Turkish。
可以选的电影多如牛毛,为了缩小范围,伴侣还列出了它们的类型。
定义可区分联合Genre,用以下用例来表示这些类型:Crime、Horror、Romance 和 Thriller。
如前所述,伴侣想出了五种不同的活动:玩桌游、放松一下、看电影、去餐厅和散步。
定义可区分联合Activity,用以下用例来表示这些活动类型:
BoardGame:没有关联数据。Chill:没有关联数据。Movie:以它的Genre作为关联数据。Restaurant:以它的Cuisine作为关联数据。Walk:以一个int作为关联数据,表示要走的公里数。终于可以给伴侣的想法评分了。你对伴侣这些想法的感受是这样的:
实现一个名为rateActivity的函数,它接收一个Activity值,并根据上面的感受返回Approval:
rateActivity (Restaurant Turkish)
// => Maybe