F# 4.5 中的 byref 返回



我正在尝试将F#样式的接口添加到具有byref返回方法的类型中。 代码如下:

type IPool<'P, 'T when 'T: struct> =
abstract member GetReference: ITypedPointer<'P, 'T> -> byref<'T>
let Ref<'TPool, 'P, 'T when 'TPool :> IPool<'P, 'T>> (pool: 'TPool) pointer =
pool.GetReference pointer

现在令我惊讶的是,在我引入IPool界面之前,类似的事情工作正常。在此之前,Ref 本身包含一个像&pool.data.[idx]这样的实现,并且工作正常。

我尝试安装F#工具的夜间构建,因为最新版本不正式支持byref返回,并且最近完成了引入它们的PR:https://github.com/Microsoft/visualfsharp/pull/4888

但是,我仍然在Visual Studio中得到error FS3209: The address of the variable 'copyOfStruct' cannot be used at this point. A method or function may not return the address of this local value.outref<T>型似乎也仍然不可用。我错过了什么吗?

我还尝试删除pointer参数,只需返回pool.GetReference只会收到不同的错误消息。

补充:最终目标是能够做到

let aref = Ref pool ptr
let bref = Ref pool ptr
aref <- 42
assert(aref = bref)

例如,给调用者一个对内部存储器的直接引用,通常由一个数组支持,类似于Span<T>。我这样做是出于性能原因,因此不可以每次调用 Ref 进行分配。

出于某种原因,减少泛化有助于消除错误:

let Ref<'P, 'T when 'T: struct> (pool: IPool<'P, 'T>) pointer = pool.GetReference pointer

解决方案由

https://github.com/Microsoft/visualfsharp/issues/5366#issuecomment-407521220

虽然它没有解释为什么原始代码无法编译。

我认为返回byref类型不是标准做法。 此类型实际上适用于方法参数,主要用于具有outref参数的 C# 互操作。 看看这个 StackOverflow 问题以获得很好的解释。

您可以做的是更改接口上的方法,以采用ITypedPointer<'P,'T>元组并byref<'T>(不允许使用byref与柯里参数一起使用(并返回unit。 然后,可以像使用 C# 中的out参数调用任何标准 .NET 方法一样调用GetReference。 那看起来像这样:

type ITypedPointer<'P, 'T> = interface end
type IPool<'P, 'T when 'T: struct> =
abstract member GetReference: ITypedPointer<'P, 'T> * byref<'T> -> unit
let Ref<'TPool, 'P, 'T when 'TPool :> IPool<'P, 'T>> (pool: 'TPool) pointer =
let mutable value = Unchecked.defaultof<'T>
pool.GetReference(pointer, &value)
value

相关内容

  • 没有找到相关文章

最新更新