Union类型(Union Types,Discriminated Unions)
考虑下面的枚举值:
理论上,一个card实例只有一种可能的取值,但由于enum本质上只是整数,您不能确定它的值是否是有效的,在C#中,你可以这么写:
CardSuit invalid2 = CardSuit.Club | CardSuit.Diamond;
另外,考虑下面的情形。如果您需要扩展一个enum:
Title枚举可以工作地很好,但一段时间后,如果需要添加一个“Ms”值,那么每一个switch语句都面临一个潜在的bug。当然您可以尝试修复所有的代码,却难免会发生遗漏。
枚举可以很好地表达某些概念,但是却无法提供足够的编译器检查。F#中的Union类型可设定为一组有限的值:数据标签(data tag)。例如,考虑一个表示微软员工的Union:
| BillGates
| SteveBalmer
| Worker of string
| Lead of string * MicrosoftEmployee list
如果有一个MicrosoftEmployee类型的实例,您就知道它必定是{BillGates,SteveBalmer,Worker,Lead}之一。另外,如果它是Worker,您可以知道有一个字符串与之关联,也许是他的名字。我们可以轻松地创建Union类型,而后使用模式匹配(下一小节)来匹配它们的值。
let printGreeting (emp : MicrosoftEmployee) =
match emp with
| BillGates -> printfn "Hello, Bill"
| SteveBalmer -> printfn "Hello, Steve"
| Worker(name) | Lead(name, _)
-> printfn "Hello, %s" name
现在假设需要扩展Union类型:
| BillGates
| SteveBalmer
| Worker of string
| Lead of string * MicrosoftEmployee list
| ChrisSmith
我们会看到一些编译器警告信息:

编译器检测到您没有匹配Union的每一个数据标签,发出了警告。像这样的检查会避免很多bug,要了解
模式匹配(Pattern Matching)
模式匹配看起来像是增强版的switch语句,允许您完成分支型控制流程。除了跟常数值进行比较外,还可以捕获新的值。比如在前面的例子中,我们在匹配Union数据标签时绑定了标识符“name”。
match emp with
| BillGates -> printfn "Hello, Bill"
| SteveBalmer -> printfn "Hello, Steve"
| Worker(name) | Lead(name, _)
-> printfn "Hello, %s" name
还可以对数据的“结构”进行匹配,比如对列表(list)进行匹配。(还记得吗,x :: y表示x为列表的一个元素,y是x之后的元素,而[]则是空列表。)
match aList with
| [] -> 0
| a :: [] -> 1
| a :: b :: [] -> 2
| a :: b :: c :: [] -> 3
| _ -> failwith "List is too big!"
在这个匹配的最后,我们使用了通配符“_”(下划线),它匹配任意值。如果aList变量包含多于三个的元素,最后的模式子句将执行,并抛出一个异常。模式匹配还可以我们执行任意表达式来确定模式是否匹配(如果表达式的值为false,则不匹配)。
match x with
| _ when x % 2 = 0 -> false
| _ when x % 2 = 1 -> true
我们甚至可以使用动态类型测试进行匹配:
match x with
| :? string -> "x is a string"
| :? int -> "x is a int"
| :? System.Exception -> "x is an exception"
| :? _ -> "invalid type"
记录类型(Records)
在声明包含若干个公有属性的类型时,记录类型是一种轻量级的方式。它的一个优势是,借助于类型推演系统,编译器可以通过值的声明得出适当的记录类型。
let whiteHouse = {Name = "The White House"; Address = "1600 Pennsylvania Avenue";
Zip = 20500}
在上面的例子中,首先定义了“Address”类型,那么在声明它的实例时,无须显式地使用类型注解,编译器可根据字段(属性)的名称自行得出类型的信息。所以whiteHouse的类型为Address。