我创建了一个简单的函数,它将签名'a -> 'b -> 'c option
的常见F#函数包装到更符合C#的&#34;功能为:'a -> b -> byref<'c> -> bool
。但不知何故,当我尝试在类中包装这样的方法时,我得到错误FS0001,我无法找到错误。
以下代码
open System
open System.Runtime.InteropServices
// Given a function, f: 'a -> 'b -> 'c option returns
// A new function g: 'a -> 'b -> byref<'c> -> bool
let wrapOptionF f a b (g:byref<'c>) =
match f a b with
| Some v ->
do g <- v
true
| None ->
false
let tryDivide (a:int) (b:int) =
match Math.DivRem(a,b) with
| v, 0 -> Some v
| _ -> None
type TryDivideWrapper() =
static member TryDivide(a, b, [<Out>]cRef:byref<int>) : bool =
let f = wrapOptionF tryDivide a b
f cRef
违规行为f cRef
。
答案 0 :(得分:5)
This post包含更深入的解释,但简而言之,您可以使用以下内容替换最终的类型定义:
type TryDivideWrapper() =
static member TryDivide(a, b, [<Out>]cRef:byref<int>) : bool =
wrapOptionF tryDivide a b &cRef
原因是您的wrapOptionF
需要byref
个参数。但是,byref<int>
实际上不是int
或int ref
这样的类型 - 它只是向编译器指示您的参数应该通过引用传递(例如C#中的out
)。但是,进入您的函数后,您所拥有的是常规int
。
修改:请注意,智能感知会将cRef
显示为byRef<int>
类型。但是,如果您将另一个变量绑定到cRef
,您会看到所获得的类型是常规int
。您可以将此行放在TryDivide
内,然后将鼠标悬停在a
上以查看它:
let a = cRef
使用&
运算符告诉编译器您通过引用将cRef
传递给f
- 这正是f
所需要的 - 使类型系统满意。我使用C#项目对此进行了测试,TryDivideWrapper.TryDivide(a, b, out c)
按预期工作。加入@MarkSeemann的tryDivide
你应该很高兴。
答案 1 :(得分:1)
我不确定我理解原因,但这似乎有效:
fun File.copyInputStreamToFile(inputStream: InputStream) {
inputStream.use { input ->
this.outputStream().use { fileOut ->
input.copyTo(fileOut)
}
}
}
顺便说一句,OP type TryDivideWrapper() =
static member TryDivide(a, b, [<Out>]cRef:byref<int>) : bool =
wrapOptionF tryDivide a b &cRef
实现会在tryDivide
上引发异常。这是一个有效的替代实现:
tryDivide 1 0
FSI:
let tryDivide (a:int) (b:int) =
if b = 0
then None
else Some (a / b)