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