2013-04-04 2 views
1

Я пытаюсь закодировать тип, представляющий указатель в устройстве GPU, и он должен действовать как массив с индексированным свойством для get и set. Я не вижу проблем, если тип элемента является примитивным типом, но когда я использую struct, я не могу изменить его значение.Как создать изменяемый тип коллекции, например 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 просто возвращает значение «T», поэтому я не могу его мутировать. Но системный массив работает.

У кого-нибудь есть опыт? для создания типа работает как массив? который, я надеюсь, что функция get от проиндексированного свойства возвращает mutable ref вместо значения.

ответ

2

Вы не можете создать тип, который работает со структурами, подобными массиву, потому что язык и среда выполнения предоставляют специальную обработку массивам, которые не получают другие классы.

С помощью массива выражение, обращающееся к элементу, являющемуся структурой, как и в вашей функции foo, заставляет элемент быть непосредственно модифицированным на месте. collection.[0] эффективно настраивает «указатель» или «ссылку» на элемент, к которому затем применяется выражение .x, что позволяет вам манипулировать объектом на месте.

Для других классов индексатор - это еще одна функция, означающая, что возвращается копия значения. Таким образом, в функции barcollection.[0] создает копию возвращаемого значения вместо ссылки, которую вы получаете из массива. Поскольку .x будет изменять временную копию, компилятор выдает ошибку, которую вы видите. (Очень похожее предупреждение будет происходить в C# или VB для аналогичного кода.) Как следует из сообщения, вам нужно создать переменную для хранения копии, изменить копию и назначить ее обратно на collection.[0].

+0

Спасибо, это печально. Я знаю, что причина в индексированном свойстве Item возвращает только скопированное значение, а не ссылку на что-то. Но на самом деле меня это не волновало. Я склонен использовать этот кусок кода в цитате. И я переведу его в другой байт-код LLVM. Так что я хочу именно эту лучшую грамматику. Есть ли атрибут, который может контролировать поведение компилятора? –

+0

Я также проверил интерфейс IList <'T> в .NET, поможет ли это реализовать? –

+0

@XiangZhang Насколько мне известно, вы ничего не можете сделать, чтобы компилятор дал вашему типу обработку массива для индексаторов. В зависимости от вашего уровня перевода вы можете создать прокси-тип, который является классом для целей грамматического кода, и перевести эти цитаты на байт-код с использованием структуры. –

Смежные вопросы