2013-04-04 86 views
1

我試圖編寫一個類型來表示GPU設備中的一個指針,它應該像一個數組一樣,具有獲取和設置的索引屬性。如果元素類型是基本類型,我不會遇到任何問題,但是當我使用結構時,我無法更改其成員的值。如何創建像Array這樣的可變集合類型?

看到這個代碼:

#nowarn "9" 

open System 
open System.Runtime.InteropServices 

[<Struct;StructLayout(LayoutKind.Sequential)>] 
type MyStruct = 
    val mutable x : int 
    val mutable y : int 
    val mutable z : int 

    override this.ToString() = sprintf "(%d,%d,%d)" this.x this.y this.z 

let deviceOnly() = failwith "this function should be used in quotation only" 

type DevicePtr<'T>(h:nativeint) = 
    member this.Handle = h 
    member this.Item with get (idx:int) : 'T = deviceOnly() and set (idx:int) (value:'T) : unit = deviceOnly() 
    member this.Reinterpret<'T2>() = DevicePtr<'T2>(h) 
    member this.Volatile() = DevicePtr<'T>(h) 
    static member (+) (ptr:DevicePtr<'T>, offset:int) = DevicePtr<'T>(ptr.Handle + nativeint(offset * sizeof<'T>)) 

let test() = 
    let mutable test1 = MyStruct() 
    test1.x <- 1 

let foo (collection:MyStruct[]) = 
    collection.[0].x <- 1 

let bar (collection:DevicePtr<MyStruct>) = 
    collection.[0].x <- 1 
    //error FS0257: 
    // Invalid mutation of a constant expression. 
    // Consider copying the expression to a mutable local, e.g. 'let mutable x = ...'. 

因此,類型是DevicePtr <「T>,它已索引屬性項目與get和set方法。但get方法只返回'T'的值,所以我不能改變它。但系統陣列起作用。

任何人都有這樣的經驗?創建一個類似數組的類型?我希望被索引的屬性的get函數返回一個可變的ref而不是一個值。

回答

2

你不能創建一個類似於數組的結構的類型,因爲語言和運行時會對其他類不能獲得的數組進行特殊處理。

對於一個數組,訪問作爲結構的元素(如foo函數)中的表達式會導致元素被直接修改。 collection.[0]正在有效地將.x表達式應用於的元素的「指針」或「引用」設置爲一個元素,從而允許您就地操作該對象。

對於其他類,索引器只是另一個函數,意味着正在返回值的副本。因此,在bar函數中,collection.[0]將創建返回值的副本,而不是從數組中獲取的引用。由於.x將修改臨時副本,因此編譯器會發出您看到的錯誤。 (對於類似的代碼,C#或VB中會出現非常類似的警告。)如消息所示,您需要創建一個變量來保存副本,修改副本並將其分配回collection.[0]

+0

謝謝,這很傷心。我知道原因是索引屬性Item只是返回一個複製的值,而不是某個東西的引用。但實際上我並不關心它。我傾向於在引用中使用這段代碼。我將把它翻譯成不同的LLVM字節碼。所以我想要的只是這個更好的語法。有沒有可以控制編譯器行爲的屬性? – 2013-04-04 04:42:34

+0

我也在.NET中檢查了IList <'T>接口,它有助於實現它嗎? – 2013-04-04 04:43:33

+0

@XiangZhang據我所知,沒有什麼可以讓編譯器給你的類型索引器的數組處理。根據您的翻譯層,您可以創建一個代理類型,該類型是用於引用語法目的的類,並使用該結構將這些引用轉換爲字節碼。 – 2013-04-04 13:05:00