使用F#Struct和Explicit LayoutKind创建带标记的联合

Bar*_*ski 4 f#

我正在尝试创建F#等效的标记联合。我需要在应用程序代码的热路径中使用它,在此情况下,有区别的联合会导致过多的堆分配。

这是示例:

[<Struct; StructLayout(LayoutKind.Explicit)>]
type Result =
    [<DefaultValue; FieldOffset 0>]
    val mutable IsAsync : bool
    [<DefaultValue; FieldOffset 1>] 
    val mutable Async : Async<obj>
    [<DefaultValue; FieldOffset 1>] 
    val mutable Sync : obj
Run Code Online (Sandbox Code Playgroud)

但是,当我想为其提供某种创建方法时,问题就开始了。

例子1

static member Async(a:Async<obj>) = Result(IsAsync = true; Async=a)
static member Sync(s:obj) = Result(IsAsync = false; Sync=s)
Run Code Online (Sandbox Code Playgroud)

引发成员或对象构造函数'Result'接受0个参数,但此处指定为1。必需的签名为'Result()'编译错误。

例子2

new(a:Async<obj>) = { IsAsync = true; Async = a; }
new(s:obj) = { IsAsync = false; Sync=s }
Run Code Online (Sandbox Code Playgroud)

引发无关字段被赋予值编译错误。

kvb*_*kvb 5

您有三个问题:

  1. 您需要使用逗号(,)而不是分号(;)分隔构造函数参数。
  2. 对象引用必须在指针大小的边界上对齐。因此,在x64上,对象引用的偏移量必须为8。
  3. 静态和实例成员名称不应重叠。

这对我有用:

[<Struct; StructLayout(LayoutKind.Explicit)>]
type Result =
    [<DefaultValue; FieldOffset 0>]
    val mutable IsAsync : bool
    [<DefaultValue(false); FieldOffset 8>] 
    val mutable Async : Async<obj>
    [<DefaultValue; FieldOffset 8>] 
    val mutable Sync : obj

    static member MakeAsync(a:Async<obj>) = Result(IsAsync = true, Async=a)
    static member MakeSync(s:obj) = Result(IsAsync = false, Sync=s)
Run Code Online (Sandbox Code Playgroud)