如何在F#中创建一个值类型的Union类型?

普通F#区分联合是引用类型。 如何在F#中创建一个简单的 (非递归的,只有值类型的字段)联合类型,它是一个值类型?

根据一些互联网搜索,我当前(非工作)的尝试看起来如下:

[] type Float = [] [] val mutable Val1 : float [] [] val mutable Int1 : int new (a:float) = {Val1 = a} 

以下博客文章显示通过C#显示可能的内容

我知道上面的内容不是F#的习惯用法,但我试图优化我的部分应用程序的性能,并且分析清楚地表明堆分配(JIT_new)的成本是导致我的性能瓶颈的原因。一个简单的联合类型是满足我需求的完美数据结构,而不是堆分配的。

首先,我可能不会这样做,除非我有充分的理由。 在大多数情况下,结构和引用类型之间的区别并不是那么大 – 根据我的经验,它只对你有一个非常大的数组(然后结构让你分配一个大的内存块)很重要。

也就是说,看起来F#不喜欢你的例子中的构造函数代码。 我真的不确定为什么(它似乎正在做一些对重叠结构不起作用的检查),但以下是诀窍:

 [] type MyStruct = [] val mutable Val1 : float [] val mutable Int1 : int static member Int(a:int) = MyStruct(Int1=a) static member Float(f:float) = MyStruct(Val1=f) 

如果我真的想要使用它,我会添加另一个包含10字段Tag ,具体取决于struct所代表的情况。 然后你可以使用活动模式对其进行模式匹配,并获得一些有区别的联盟的安全性:

 let (|Float|Int|) (s:MyStruct) = if s.Tag = 0 then Float(s.Val1) else Int(s.Int1) 

现在,F#支持结构联合,有关详细信息,请参阅F#RFC FS-1014 。 简而言之:

 // Single case: [] type UnionExample = U of int * int * bool // Multi-case: [] type Shape = | Circle of radius: double | Square of side: int 

结构记录的主要区别:

  • 您不能对定义的相同类型进行循环引用。 例如:类型T = U的T
  • 您也无法调用默认的ctor,就像使用普通的F#结构一样。
  • 对于多案例结构联合,每个案例必须具有唯一的名称。