How to create a Union type in F# that is a value type?

十年热恋 提交于 2019-12-05 21:46:41

First of all, I would probably not do this, unless I had very good reasons. In most cases, the difference between structs and reference types is not really that big - in my experience, it only matters when you have a very large array of them (then structs let you allocate one big memory chunk).

That said, it looks like F# does not like the constructor code in your example. I'm really not sure why (it seems to be doing some check that does not quite work for overlapping structs), but the following does the trick:

[<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)

If I actually wanted to use this, I would add another field Tag containing 1 or 0 depending on which case your struct represents. Then you could pattern match on it using an active pattern and get some of the safety of discriminated unions back:

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

Struct unions are now supported by F#, see F# RFC FS-1014 for details. In short:

// Single case:

[<Struct>]
type UnionExample = U of int * int * bool

// Multi-case:

[<Struct>]
type Shape =
   | Circle of radius: double
   | Square of side: int

Key differences in struct records:

  • You cannot have cyclic references to the same type being defined. ex: type T = U of T
  • You also cannot call the default ctor, like you could with normal F# structs.
  • For multi-case struct unions, each case must have a unique name.
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!