2011-01-11 76 views
2

到目前爲止,我所見過的任何示例似乎都沒有解決編組包含遞歸引用的結構聯合的結構的問題。我正試圖爲包含這些結構的結構編寫一個編組器,並且迄今爲止失敗了。F#P /調用封送遞歸結構

例如:

typedef enum { 
    My_StructA = 0x7878, 
    My_StructB 
} MyStructTag; 

typedef struct _MyStruct MyStruct; 

struct _MyStruct { 
    MyStructTag discriminator; 
    union { 
     struct { 
      int a; 
      int b; 
     } StructA; 

     struct { 
      int c; 
      MyStruct* d; 
     } StructB; 
    } MyUnion; 
}; 

我試圖定義結構如下:

type MyStructTag = 
    | My_StructA = 0x7878 
    | My_StructB = 0x7879 

[<Struct; StructLayout(LayoutKind.Sequential)>] 
type StructA = 
    val mutable a : int 
    val mutable b : int 

[<Struct; StructLayout(LayoutKind.Sequential)>] 
type StructB = 
    val mutable c : int 
    val mutable d : MyStruct 

[<Struct; StructLayout(LayoutKind.Explicit)>] 
type MyStruct = 
    [<FieldOffset(0)>] val discriminator : MyStructTag 
    [<FieldOffset(4)>] val structA : StructA 
    [<FieldOffset(4)>] val structB : StructB 

注意,我不屑於明確定義MYSTRUCT的原因是爲了讓自己充分利用元帥。 OffsetOf()和Marshal.SizeOf()爲此結構編寫自定義封送拆分器時。從我看到的情況來看,編寫自定義編組器是處理工會的唯一方法。如果我錯了,參考將不勝感激!

寫上面的代碼時,收到的錯誤是:

error FS0039: The type 'MyStruct' is not defined 

我假定這是因爲只有識別聯合類型可以被遞歸地定義。但是,我不知道有任何其他方式來表示F#中的這些結構。

預先感謝您的時間。

回答

4

你有兩個問題。首先,任何相互遞歸類型(是否可識別聯合,類或結構)需要使用

type A = ... 
and B = ... 

而不是

type A = ... 
type B = ... 

(請注意,屬性可以來之前或之後的定義單詞type,但僅在單詞and ...之後)。但是,如果你嘗試這樣做,你會發現你只是得到了一個不同的錯誤,因爲結構不能直接作爲對方的字段遞歸。如果結構A具有一個結構B的字段,並且結構B具有一個結構A的字段(並且其中任何一個具有任何其他字段),那麼大小將是無限的。請注意,您的C代碼也是如此 - StructB包含指針MyStruct,而不是MyStruct本身。在.NET中,您可以使用IntPtr - 在F#中,您可以使用nativeint別名或nativeptr<MyStruct>。試試這個:

open System.Runtime.InteropServices 

type MyStructTag = 
| My_StructA = 0x7878 
| My_StructB = 0x7879 

[<Struct; StructLayout(LayoutKind.Sequential)>] 
type StructA = 
    val mutable a : int 
    val mutable b : int 

[<Struct; StructLayout(LayoutKind.Sequential)>] 
type StructB = 
    val mutable c : int 
    val mutable d : nativeptr<MyStruct> 

and [<Struct; StructLayout(LayoutKind.Explicit)>]MyStruct = 
    [<FieldOffset(0)>] val discriminator : MyStructTag 
    [<FieldOffset(4)>] val structA : StructA 
    [<FieldOffset(4)>] val structB : StructB 
+0

非常感謝!這做到了。一個問題 - 我從來沒有見過nativeptr <|在這裏插入非託管類型|>結構。 MSDN沒有一個很好的解釋,谷歌代碼搜索沒有產生任何啓發性的片段。 – arachnid 2011-01-11 18:36:43