如果我在F#中具有以下枚举:
type Note =
| C = 0
| D = 2
| E = 4
| F = 5
| G = 7
| A = 9
| B = 11
但是在某些时候,我需要其中的项目的序数,例如Note.C = 1, Note.D = 2,
等。显然,在其他语言中,foo.ordinal()
也可以工作,但是在这里必须使用这样的功能:
let getNoteOrdinal = function
|Note.C -> 1
|Note.D -> 2
|Note.E -> 3
|Note.F -> 4
//etc
该功能是否必要或有更好的选择?
答案 0 :(得分:4)
.NET中的枚举只是整数类型之上的一层,在这种情况下,您的值是int
。
对于每个the docs,您可以进行简单的转换来获取该值,例如:
let value = int Note.B
在这种情况下,value
将为11
。
要找到序数,您可以利用一个内置函数,该函数为您按顺序提供所有值的数组,然后找到您要查找的值的索引。例如:
let getNoteOrdinal (note: Note) =
let values = Enum.GetValues(typeof<Note>)
Array.IndexOf(values, note) + 1
let value = getNoteOrdinal Note.E
在这种情况下,value
将为3
。
您可以按照@ReedCopsey的建议更进一步,并创建一个通用函数,该函数将为您提供 any 枚举值的序数:
let getEnumOrdinal (e: 'a when 'a : enum<'b> and 'a : equality) =
let values = Enum.GetValues(e.GetType())
Array.IndexOf(values, e) + 1
答案 1 :(得分:1)
我建议不要在F#中完全使用枚举,除非与另一种.NET语言互操作需要此枚举。您可以使用已区分的联合并将注释值存储在数组中(这是模块级别的值,在应用程序启动时将对其进行一次评估)。然后,您可以编写使用数组的函数。
type Note = C | D | E | F | G | A | B
let noteValues =
[| C, 0
D, 2
E, 4
F, 5
G, 7
A, 9
B, 11 |]
let getNoteValue note =
noteValues |> Array.find (fun (n, _) -> note = n) |> snd
let getNoteOrdinal note =
noteValues |> Array.findIndex (fun (n, _) -> n = note) |> (+) 1
用法示例:
getNoteValue C // 0
getNoteValue D // 2
getNoteOrdinal C // 1
getNoteOrdinal D // 2