F# 枚举类型
最后修改于 2025 年 5 月 24 日
本文探讨了如何在 F# 中有效使用枚举类型来表示命名值的固定集合。
枚举类型(或枚举)是一种由一组命名常量组成的独立类型。枚举提供了一种为值创建有意义的符号名称的方法,使代码更具可读性和可维护性。在 F# 中,枚举是继承自 System.Enum 的值类型。
F# 支持两种创建枚举的方法:一种是使用 type 关键字配合 | 语法创建简单的枚举,另一种是使用 [<Flags>] 属性创建位标志枚举。枚举可以与它们的底层整型类型相互转换。
基本枚举定义
在 F# 中定义枚举最简单的方法是使用区分联合 (discriminated union) 语法。
type Color =
| Red
| Green
| Blue
| Yellow
let favorite = Color.Blue
match favorite with
| Color.Red -> printfn "Your favorite color is Red"
| Color.Green -> printfn "Your favorite color is Green"
| Color.Blue -> printfn "Your favorite color is Blue"
| Color.Yellow -> printfn "Your favorite color is Yellow"
此示例演示了基本的颜色枚举定义和模式匹配。
type Color =
| Red
| Green
| Blue
| Yellow
这定义了一个简单的枚举类型,有四个可能的值。每个值都是区分联合的一个 case。
λ dotnet fsi main.fsx Your favorite color is Blue
冗余限定符
在 F# 中,一旦定义了一个区分联合类型,在进行模式匹配时就不需要显式引用其名称。您可以直接匹配其 case。这使得 Color 限定符在 match 表达式内部使用时是冗余的。
type Color =
| Red
| Green
| Blue
| Yellow
let favorite = Blue // No need for Color.Blue
match favorite with
| Red -> printfn "Your favorite color is Red"
| Green -> printfn "Your favorite color is Green"
| Blue -> printfn "Your favorite color is Blue"
| Yellow -> printfn "Your favorite color is Yellow"
当在 Color 已被识别的同一作用域内引用一个 case 时,F# 会推断 Red、Green、Blue 和 Yellow 指的是 Color 类型。因此,您可以直接使用 case,而无需在它们前面加上 Color. 前缀。
λ dotnet fsi main.fsx Your favorite color is Blue
因此,除非存在歧义——例如,当多个区分联合具有重叠的名称时——否则显式地在 case 前加上 Color. 前缀是不必要的。这种行为在 F# 中是一致的,有助于保持代码的整洁和简洁。
带有底层值的枚举
枚举可以为每个 case 分配显式的底层值。
type Priority =
| Low = 0
| Medium = 1
| High = 2
| Critical = 3
let currentPriority = Priority.High
printfn "Priority value: %d" (int currentPriority)
printfn "Priority name: %A" currentPriority
此示例显示了一个为 case 分配了显式整数值的枚举。
type Priority =
| Low = 0
| Medium = 1
| High = 2
| Critical = 3
每个枚举 case 都被分配了一个特定的整数值。int 函数将枚举转换为其底层值。
λ dotnet fsi main.fsx Priority value: 2 Priority name: High
标志枚举
F# 使用 [<Flags>] 属性支持位标志枚举。
open System
[<Flags>]
type Permissions =
| None = 0
| Read = 1
| Write = 2
| Execute = 4
| All = 7
let userPermissions = Permissions.Read ||| Permissions.Write
printfn "User permissions: %A" userPermissions
printfn "Can read: %b" (userPermissions.HasFlag(Permissions.Read))
printfn "Can execute: %b" (userPermissions.HasFlag(Permissions.Execute))
此示例演示了一个用于表示权限组合的标志枚举。
[<Flags>]
type Permissions =
| None = 0
| Read = 1
| Write = 2
| Execute = 4
| All = 7
[<Flags>] 属性启用了按位运算。值是 2 的幂,以便进行组合。
λ dotnet fsi main.fsx User permissions: Read, Write Can read: true Can execute: false
枚举解析
枚举可以从字符串解析并转换为字符串。
type Season =
| Spring = 0
| Summer = 1
| Autumn = 2
| Winter = 3
let success, parsedSeason = System.Enum.TryParse<Season>("Summer")
let seasonString = parsedSeason.ToString()
printfn "Parse success: %b" success
printfn "Parsed value: %A" parsedSeason
printfn "String representation: %s" seasonString
此示例显示了如何在枚举和字符串之间进行转换。
let success, parsedSeason = System.Enum.TryParse<Season>("Summer")
Enum.TryParse 安全地尝试将字符串转换为枚举值。
λ dotnet fsi main.fsx Parse success: true Parsed value: Summer String representation: Summer
枚举迭代
您可以迭代枚举类型的_所有_值。
open System
type Direction =
| North = 0
| East = 1
| South = 2
| West = 3
let allDirections = Enum.GetValues(typeof<Direction>)
printfn "All directions:"
for dir in allDirections do
printfn "- %A" dir
此示例演示了如何获取枚举类型的_所有_值。
let allDirections = Enum.GetValues(typeof<Direction>)
Enum.GetValues 返回一个包含枚举_所有_值的数组。
λ dotnet fsi main.fsx All directions: - North - East - South - West
带模式匹配的枚举
枚举与 F# 的模式匹配功能配合良好。
type TrafficLight =
| Red
| Yellow
| Green
let getNextLight current =
match current with
| Red -> Green
| Green -> Yellow
| Yellow -> Red
let light = TrafficLight.Red
let nextLight = getNextLight light
printfn "Current light: %A" light
printfn "Next light: %A" nextLight
此示例显示了如何使用模式匹配与枚举。
match current with | Red -> Green | Green -> Yellow | Yellow -> Red
模式匹配提供了一种处理不同枚举 case 的简洁方法。
λ dotnet fsi main.fsx Current light: Red Next light: Green
枚举扩展方法
您可以使用其他功能扩展枚举。
type CardSuit =
| Hearts = 0
| Diamonds = 1
| Clubs = 2
| Spades = 3
module CardSuitExtensions =
type CardSuit with
member this.Color =
match this with
| CardSuit.Hearts | CardSuit.Diamonds -> "Red"
| CardSuit.Clubs | CardSuit.Spades -> "Black"
| _ -> "Unknown"
let suit = CardSuit.Hearts
printfn "Suit: %A, Color: %s" suit (suit.Color)
此示例向 CardSuit 枚举添加了一个 Color 属性。
type CardSuit with
member this.Color =
match this with
| CardSuit.Hearts | CardSuit.Diamonds -> "Red"
| CardSuit.Clubs | CardSuit.Spades -> "Black"
| _ -> "Unknown"
扩展方法允许向现有枚举类型添加功能。
λ dotnet fsi main.fsx Suit: Hearts, Color: Red