F# 4.5 中的 byref return

byref return in F# 4.5

我正在尝试向具有 byref return 方法的类型添加 F# 样式的接口。 这是代码:

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 returns,介绍它们的 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 参数,只是 return pool.GetReference 只得到不同的错误消息。

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

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

例如为调用者提供对内部存储器的直接引用,通常由数组支持,类似于 Span<T>。我这样做是出于性能原因,所以在每次调用 Ref.

时都分配是不可行的

我认为 return byref 类型不是标准做法。这种类型实际上用于方法参数,主要用于与 outref 参数的 C# 互操作。看看 this Whosebug question 以获得很好的解释。

你可以做的是改变你界面上的方法来获取 ITypedPointer<'P,'T>byref<'T> 的元组(柯里化参数不允许使用 byref)和 return 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

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

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

解决方案由

提供

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

虽然没有解释原代码编译不通过的原因