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

Sam*_*Sam 3 .net c# f# pointers discriminated-union

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

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

[<StructLayout(LayoutKind.Explicit)>]
type Float =
    [<DefaultValue>] [<FieldOffset 0>] val mutable Val1 : float
    [<DefaultValue>] [<FieldOffset 0>] val mutable Int1 : int
    new (a:float) = {Val1 = a}    
Run Code Online (Sandbox Code Playgroud)

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

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

Tom*_*cek 11

首先,我可能无法做到这一点,除非我有非常好的理由.在大多数情况下,结构和引用类型之间的区别并不是那么大 - 根据我的经验,只有当你有一个非常大的数组(然后结构允许你分配一个大的内存块)时才重要.

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

[<Struct; StructLayout(LayoutKind.Explicit)>]
type MyStruct =
    [<DefaultValue; FieldOffset 0>] 
    val mutable Val1 : float
    [<DefaultValue; FieldOffset 0>] 
    val mutable Int1 : int
    static member Int(a:int) = MyStruct(Int1=a)
    static member Float(f:float) = MyStruct(Val1=f)
Run Code Online (Sandbox Code Playgroud)

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

let (|Float|Int|) (s:MyStruct) = 
  if s.Tag = 0 then Float(s.Val1) else Int(s.Int1)
Run Code Online (Sandbox Code Playgroud)