F# 枚举类型的类型约束

4

我想编写一个F#函数,它接受一个通用的枚举值,并将其基础整数值加倍。幸运的是,有一个名为int的内置函数可以将枚举转换为整数,因此这应该很容易实现,对吧?这是我的第一次尝试:

let doubler (value : 't when 't : enum<int>) =
    2 * (int value)

很不幸,这导致以下编译器消息:

Program.fs(2,10): 警告 FS0064: 这个结构使代码比类型注释所示的更不通用。类型变量't已被限制为类型'int'。

Program.fs(2,10): 错误 FS0071: 应用类型推断变量的默认类型'int'时出现类型约束不匹配。类型'int'不是CLI枚举类型。请参见Program.fs(1,28)-(1,42)。考虑添加进一步的类型约束

我做错了什么?在F#中有更好的方法从泛型枚举值中提取底层整数吗?

enum 的作用是将一个值转换为其表示形式。编译器会为您添加约束条件。请参见下文。 - s952163
1个回答

2
你需要使用 EnumToValue
open FSharp.Core.LanguagePrimitives

let doubler xEnum =
        2 * EnumToValue(xEnum)

type ColorEnum =    
            | Red=0 
            | Yellow=1 
            | Blue=2

let blue = ColorEnum.Blue

doubler blue
//val it : int = 4

如果您查看doubler的类型签名:

val doubler : xEnum:'a -> int when 'a : enum

关于您遇到的第一个错误,int是特殊的,因为它也是一个函数。正如您所指出的,您可以在枚举中使用基础类型约束,但在这种情况下,请明确指定类型,以避免混淆:

let double2 (x:'T when 'T:enum<int32>) =
   2 * EnumToValue(x)

很遗憾,您仍然无法在不使用EnumToValue的情况下转换为int。可能是编译器问题或其他原因。也许EnumToValue的内部可以给出一些提示?


@brianberns 这是因为没有通用的枚举(我想)。如果您想要约束,则需要说let doubl2 (x:'T when 'T:enum<ColorEnum>) =。这将仅约束x为一个类型的枚举。而且你还会遇到“int”问题。我不知道它的根本原因是什么。 - s952163
1
我不明白你的意思。虽然文档上说enum<int>并非用于常规情况,但我相信它是F#中合法的类型约束。请参见https://learn.microsoft.com/en-us/dotnet/articles/fsharp/language-reference/generics/constraints。 - Brian Berns
啊,我明白你的意思了。确实如此。不过让我修改一下答案。 - s952163
1
关于这个问题,还有一个评论:EnumToValue会将枚举类型装箱,然后再将其拆箱为整数。虽然这样可以正常工作,但速度较慢。我真正想要的是像本地int运算符一样高效的东西,在运行时不需要任何周期。 - Brian Berns
@brianberns 性能是一项重要特性 :-). 你能至少并行化它吗?当然可能有更好的方法。为什么不提出另一个问题,附带一些基准数据和你认为可接受的性能想法呢? - s952163
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接