我正在尝试编写一个类型来表示GPU设备中的指针,它应该像一个数组,具有get和set的索引属性。如果元素类型是基本类型,我没有问题,但是当我使用结构时,我无法更改其成员的值。
请参阅此代码:
#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&lt;'T&gt;,它使用get和set方法索引属性Item。但是get方法只返回'T的值,所以我不能改变它。但是系统阵列可以工作。
任何人都有这样的经历吗?创建类似数组的类型?我希望indexed属性的get函数返回一个可变的ref而不是一个值。
答案 0 :(得分:2)
您无法创建一个适用于数组结构的类型,因为语言和运行时对其他类无法获得的数组进行特殊处理。
对于数组,访问作为结构的元素的表达式(如foo
函数)会导致元素直接修改到位。 collection.[0]
有效地设置了一个&#34;指针&#34;或&#34;参考&#34;到应用.x
表达式的元素,允许您操作对象。
对于其他类,索引器只是另一个函数,意味着返回值的副本。因此,在bar
函数中,collection.[0]
创建返回值的副本,而不是从数组中获取的引用。由于.x
将修改临时副本,因此编译器会发出您看到的错误。 (对于类似的代码,在C#或VB中会发生非常类似的警告。)如消息所示,您需要创建一个变量来保存副本,修改副本并将其分配回collection.[0]
。