这不是使用 byref 的有效方式吗?

3
let iter2D (map: 'T byref -> unit) (arr: 'T[][]) =
    for y = 0 to arr.Length - 1 do
        let row = arr.[y]
        for x = 0 to row.Length - 1 do
            let mutable elem = arr.[y].[x]
            map &elem

最后一行显示:“此处无法使用变量 'elem' 的地址。”这是什么问题?
1个回答

8
在 F# 中,'T byref 看起来像是一个普通类型,但实际上它不是 - 它对应于 C# 中的 refout 参数,并且这些是方法参数上的特殊注释。这就是为什么在 F# 中 'T byref 有点奇怪。
我认为你不能通过普通的 F# 函数使用它,因为函数 T1 -> T2 编译为带有方法 T2 Invoke(T1 arg)FSharpFunc<T1, T2> - 你无法将 byref 类型传递给泛型(因为它不是真正的类型)。
解决方法是定义自己的委托,其中包含 byref 类型。
type FastAction<'T> = delegate of 'T byref -> unit

通过这种方式,您可以编写一个 iter2D 对数组进行直接迭代的方法:

let iter2D (map:FastAction<'T>) (arr: 'T[][]) =
    for y = 0 to arr.Length - 1 do
        let row = arr.[y]
        for x = 0 to row.Length - 1 do
            map.Invoke(&arr.[y].[x])

以下代码会改变数组中的值:
let arr = [| [| 0 |] |]
iter2D (FastAction(fun a -> a <- 10)) arr

1
你说“byref”不是真正的类型是什么意思?那么MakeByRefType()返回的是什么?IsByRef属性又是用来做什么的? - user4003407
唉,FastAction(fun bla ...)会导致2个分配...看起来没有办法避免,因为F#没有像C#那样的单独匿名委托语法。 - Asik
@Asik,自F# 4或5以来,它们已经支持了,现在可以自动转换为委托。然而,这仍然无法处理byref,因为它们不能被闭包捕获(显然),并且编译器不会检测到您只是将lambda用作委托。 - Abel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接