如何创建像Array这样的可变集合类型?

问题描述:

我试图编写一个类型来表示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而不是一个值。

你不能创建一个类似于数组的结构的类型,因为语言和运行时会对其他类不能获得的数组进行特殊处理。

对于一个数组,访问作为结构的元素(如foo函数)中的表达式会导致元素被直接修改。 collection.[0]正在有效地将.x表达式应用于的元素的“指针”或“引用”设置为一个元素,从而允许您就地操作该对象。

对于其他类,索引器只是另一个函数,意味着正在返回值的副本。因此,在bar函数中,collection.[0]将创建返回值的副本,而不是从数组中获取的引用。由于.x将修改临时副本,因此编译器会发出您看到的错误。 (对于类似的代码,C#或VB中会出现非常类似的警告。)如消息所示,您需要创建一个变量来保存副本,修改副本并将其分配回collection.[0]

+0

谢谢,这很伤心。我知道原因是索引属性Item只是返回一个复制的值,而不是某个东西的引用。但实际上我并不关心它。我倾向于在引用中使用这段代码。我将把它翻译成不同的LLVM字节码。所以我想要的只是这个更好的语法。有没有可以控制编译器行为的属性? – 2013-04-04 04:42:34

+0

我也在.NET中检查了IList 接口,它有助于实现它吗? – 2013-04-04 04:43:33

+0

@XiangZhang据我所知,没有什么可以让编译器给你的类型索引器的数组处理。根据您的翻译层,您可以创建一个代理类型,该类型是用于引用语法目的的类,并使用该结构将这些引用转换为字节码。 – 2013-04-04 13:05:00