如何在计算表达式中传递/设置 byref 参数?

Kur*_*ren 1 f# pass-by-reference computation-expression

此 F# 代码无法编译:

let DoubleString (str : string) = str + str

let ExampleSetString (str : string byref) = 
    async {
        str <- DoubleString str
        return 1
    }
Run Code Online (Sandbox Code Playgroud)

我收到以下错误消息str <- DoubleString str

byref 类型变量“str”的使用方式无效。Byref 不能被闭包捕获或传递给内部函数

我必须采用 byref 变量,将其传递到计算表达式中的一些纯函数中,然后设置此 byref 变量的值。我怎样才能做到这一点?

JL0*_*0PD 5

Dotnet 限制将 byref 变量存储到字段中,因为 byref 可以指向

  1. 数组元素 ( &ar[42])
  2. 物体的场 ( &myObject.MyField)
  3. 局部变数 (&myLocalVar
  4. 非托管内存 ( &(System.Runtime.CompilerServices.Unsafe.AsRef<myStruct> myVar))
  5. 可能更多

这会导致生命周期问题:引用的寿命可能比它所指向的变量还要长。情况 1 不会发生这种情况,但所有其他项目都可能发生。例如,给定的函数Foo调用Bar和通过引用传递值将产生此堆栈

 Baz function   Foo function   Bar function
/            \ /            \ /            \
--------------|---a----------|----b---------
Run Code Online (Sandbox Code Playgroud)

Foo已调用Bar并传递它a作为参考&aBar已将 的地址存储a到变量 中b。这意味着它b是 byref 变量,该变量的更新将更改 中的值a。当函数完成其工作时,内存被释放并且可以被其他函数重用。

 Baz function   Egg function
/            \ /            \
--------------|---c----------
Run Code Online (Sandbox Code Playgroud)

Baz已经调用了Egg函数,现在在内存中anow 位于何处c。尝试将引用更改为anow 可能会导致各种内存问题,从AccessViolation(在 Linux 中也称为分段错误)到数据损坏。当内存损坏时可能发生的最糟糕的事情是程序继续其工作。

这就是为什么 byref 变量不能被捕获到由计算表达式产生的闭包中的原因。


现在让我们回到实际问题 - 存储 Azure blob 中的字符串。我对此不熟悉,但我找到了这方面的示例,可以将其改编为以下内容

 Baz function   Foo function   Bar function
/            \ /            \ /            \
--------------|---a----------|----b---------
Run Code Online (Sandbox Code Playgroud)