F# &引用;闭包无法捕获可变变量”;是不是给了我糟糕的一天

F# &引用;闭包无法捕获可变变量”;是不是给了我糟糕的一天,f#,F#,我正在使用一个externDLL,它有一系列例程返回ReturnCodeenum,因此我编写了以下帮助函数来记录所有错误: let mutable LastError = ReturnCode.OK let mutable LastReturnCode = ReturnCode.OK let mutable TotalErrors = 0 let Run (call: unit -> ReturnCode) = LastReturnCode <- call() if Las

我正在使用一个
extern
DLL,它有一系列例程返回
ReturnCode
enum,因此我编写了以下帮助函数来记录所有错误:

let mutable LastError = ReturnCode.OK
let mutable LastReturnCode = ReturnCode.OK
let mutable TotalErrors = 0

let Run (call: unit -> ReturnCode) =
  LastReturnCode <- call()
  if LastReturnCode <> ReturnCode.OK then
    LastError <- LastReturnCode
    TotalErrors <- TotalErrors + 1
编译器给了我一个“闭包无法捕获可变变量”错误。除了到处内联
Run
之外,我还能做什么?这在C#中效果很好

(下面的extern声明示例)

[]
外部返回代码EdsCreateEvfImageRef(int-inStreamHandle,[]int&outevImageHandle);

标准解决方案是使用引用-代码变为

let CreateEvfImageRef (streamHandle: int) =
  let evfImageHandle = ref 0
  Run (fun () -> Extern.EdsCreateEvfImageRef (streamHandle, &(!evfImageHandle)))
  !evfImageHandle
let Run (call: ReturnCode) =
  LastReturnCode <- call
  if LastReturnCode <> ReturnCode.OK then
    LastError <- LastReturnCode
    TotalErrors <- TotalErrors + 1
但是,由于编译器需要
,这将不起作用!evfImageHandle
是可变的,而不是可变的

我认为真正的解决方案是更改
Run
函数,这样它就不需要闭包,而只需要返回值——在这种情况下,它至少可以工作。然后代码变为

let CreateEvfImageRef (streamHandle: int) =
  let evfImageHandle = ref 0
  Run (fun () -> Extern.EdsCreateEvfImageRef (streamHandle, &(!evfImageHandle)))
  !evfImageHandle
let Run (call: ReturnCode) =
  LastReturnCode <- call
  if LastReturnCode <> ReturnCode.OK then
    LastError <- LastReturnCode
    TotalErrors <- TotalErrors + 1
或者是更老套的解决方案。使用数组成员是可变的,并且可以被闭包捕获的事实来执行此操作

let CreateEvfImageRef (streamHandle: int) =
  let evfImageHandle =  [|0|]
  Run (fun () -> EdsCreateEvfImageRef (streamHandle, &(evfImageHandle.[0])) )
  evfImageHandle.[0]

您应该仍然能够使用
ref
类型,但在将引用传递给函数时不需要写入
&
符号-编译器将自动执行此操作:

let CreateEvfImageRef (streamHandle: int) =
  let mutable evfImageHandle = ref 0
  Run (fun () -> Extern.EdsCreateEvfImageRef (streamHandle, evfImageHandle))
  !evfImageHandle

常量表达式的无效变异。考虑将表达式复制到一个可改变的局部,例如“让可变x=……”。现在应该可以正常工作了吗?我想你也忘了去掉
&
?但这仍然让我感到类型不匹配。需要byref ref,但给定int ref,类型“byref”与类型“int”不匹配。我添加了我的extern声明作为示例。@lobsterism-我想不出比消除闭包或创建用作参数的伪数组更优雅的解决方案。类型不匹配。需要byref ref,但给定int ref,类型“byref”与类型“int”不匹配这在fsi中对F#2.0或3.0都不起作用,使用以下外部定义
[]外部内部EdsCreateEvfImageRef(int-inStreamHandle,[]int&outevImageHandle)(与lobsterism的错误相同)类型定向转换仅应用于类型成员,我怀疑这里Extern是一个模块,而不是类型
let CreateEvfImageRef (streamHandle: int) =
  let mutable evfImageHandle = ref 0
  Run (fun () -> Extern.EdsCreateEvfImageRef (streamHandle, evfImageHandle))
  !evfImageHandle