F# 相当于 C# 'out'
The F# equivalent of C#'s 'out'
我正在将 C# 库重写为 F#,我需要翻译以下代码
bool success;
instance.GetValue(0x10, out success);
F# 中的 out
关键字等效于什么?
您必须使用 reference cell。
let success = ref false
instance.GetValue(0x10, success)
// access the value
!success
您可能应该 return 一个选项或一个元组。因为 F# 具有模式匹配功能,所以您实际上不需要输出参数,因为有更好的方法 return 从一个函数中获取多个值。
所以,像这样的东西会更地道
let (value, success) = instance.GetValue(0x10)
其中 instance.GetValue 是
unit -> ('a, bool)
或者你可以return一个选项然后做一些类似
的事情
match instance.GetValue(0x10) with
| Some value -> doStuff value
| None -> failwith "Oops!"
wasatz 和 Max Malook 的回答都不完整。调用带有 out
参数的方法有 3 种方式。第二种和第三种方式也适用于 ref
参数。
对于示例,假定以下类型:
open System.Runtime.InteropServices //for OutAttribute
type SomeType() =
member this.GetValue (key, [<Out>] success : bool byref) =
if key = 10 then
success <- true
"Ten"
else
success <- false
null
还假设我们有一个该类型的实例:
let o = SomeType()
选项 1
您可以让 F# 编译器处理 out 参数,方法是将它与 return 值组合起来:
let result1, success1 = o.GetValue 10
let result2, success2 = o.GetValue 11
运行 F# 交互式中的上述行产生
val success1 : bool = true
val result1 : string = "Ten"
val success2 : bool = false
val result2 : string = null
选项 2
您可以使用可变值,通过 &
运算符传递其地址:
let mutable success3 = false
let result3 = o.GetValue (10, &success3)
let mutable success4 = false
let result4 = o.GetValue (11, &success4)
在 F# 交互中,结果是
val mutable success3 : bool = true
val result3 : string = "Ten"
val mutable success4 : bool = false
val result4 : string = null
当您委托给另一个方法时,此选项是最佳选择,因为您可以将调用方法的输出参数直接传递给被调用方法。例如,如果您要围绕 IDictionary<_,_>
实现包装器,则可以将 TryGetValue
方法编码为
//...
interface IDictionary<'TKey, 'TValue> with
member this.TryGetValue (key, value) = inner.TryGetValue (key, &value)
//...
选项 3
您可以使用参考单元格:
let success5 = ref false
let result5 = o.GetValue (10, success5)
let success6 = ref false
let result6 = o.GetValue (11, success6)
输出:
val success5 : bool ref = {contents = true;}
val result5 : string = "Ten"
val success6 : bool ref = {contents = false;}
val result6 : string = null
警告!
注意不要像在 C# 中那样对 in/out 参数使用 ref
关键字。例如,以下不会产生所需的结果:
let success7 = false
let result7 = o.GetValue (10, ref success7)
输出:
val success7 : bool = false
val result7 : string = "Ten"
为什么 success7
保持值 false
?因为 success7
是一个不可变变量。
在 C# 中,ref
提请注意您正在将对变量的引用作为参数传递给 ref
参数。它只是作为一种保证,即调用者的程序员知道该变量可能会被调用的方法修改。然而,在 F# 中,ref
创建一个新的引用单元格,其中包含 的副本 以下表达式的值。
在这种情况下,我们正在创建一个引用单元格,其中包含从 success7
变量复制的值,但不会将该新引用单元格分配给任何变量。然后我们将该引用单元格传递给 GetValue 方法,该方法修改引用单元格的内容。因为调用方法没有指向修改单元格的变量,所以它无法读取引用单元格的新值。
我认为这里还值得一提的是out参数的值不必初始化。
可以执行以下操作:
let mutable success3 = Unchecked.defaultof<bool>
let result3 = o.GetValue (10, &success3)
这在您使用数组作为输出参数调用 .NET 库函数的情况下可能很有用,即:
let mutable currFeatures = Unchecked.defaultof<PointF[]>
let mutable status = Unchecked.defaultof<byte[]>
let mutable trackError = Unchecked.defaultof<float32[]>
CvInvoke.CalcOpticalFlowPyrLK(
previousFrame,
nextFrame,
previousPoints,
Size(15,15),
2,
MCvTermCriteria(10, 0.03),
//Out params
&currFeatures,
&status,
&trackError,
//---------
LKFlowFlag.UserInitialFlow)
我正在将 C# 库重写为 F#,我需要翻译以下代码
bool success;
instance.GetValue(0x10, out success);
F# 中的 out
关键字等效于什么?
您必须使用 reference cell。
let success = ref false
instance.GetValue(0x10, success)
// access the value
!success
您可能应该 return 一个选项或一个元组。因为 F# 具有模式匹配功能,所以您实际上不需要输出参数,因为有更好的方法 return 从一个函数中获取多个值。
所以,像这样的东西会更地道
let (value, success) = instance.GetValue(0x10)
其中 instance.GetValue 是
unit -> ('a, bool)
或者你可以return一个选项然后做一些类似
的事情match instance.GetValue(0x10) with
| Some value -> doStuff value
| None -> failwith "Oops!"
wasatz 和 Max Malook 的回答都不完整。调用带有 out
参数的方法有 3 种方式。第二种和第三种方式也适用于 ref
参数。
对于示例,假定以下类型:
open System.Runtime.InteropServices //for OutAttribute
type SomeType() =
member this.GetValue (key, [<Out>] success : bool byref) =
if key = 10 then
success <- true
"Ten"
else
success <- false
null
还假设我们有一个该类型的实例:
let o = SomeType()
选项 1
您可以让 F# 编译器处理 out 参数,方法是将它与 return 值组合起来:
let result1, success1 = o.GetValue 10
let result2, success2 = o.GetValue 11
运行 F# 交互式中的上述行产生
val success1 : bool = true
val result1 : string = "Ten"
val success2 : bool = false
val result2 : string = null
选项 2
您可以使用可变值,通过 &
运算符传递其地址:
let mutable success3 = false
let result3 = o.GetValue (10, &success3)
let mutable success4 = false
let result4 = o.GetValue (11, &success4)
在 F# 交互中,结果是
val mutable success3 : bool = true
val result3 : string = "Ten"
val mutable success4 : bool = false
val result4 : string = null
当您委托给另一个方法时,此选项是最佳选择,因为您可以将调用方法的输出参数直接传递给被调用方法。例如,如果您要围绕 IDictionary<_,_>
实现包装器,则可以将 TryGetValue
方法编码为
//...
interface IDictionary<'TKey, 'TValue> with
member this.TryGetValue (key, value) = inner.TryGetValue (key, &value)
//...
选项 3
您可以使用参考单元格:
let success5 = ref false
let result5 = o.GetValue (10, success5)
let success6 = ref false
let result6 = o.GetValue (11, success6)
输出:
val success5 : bool ref = {contents = true;}
val result5 : string = "Ten"
val success6 : bool ref = {contents = false;}
val result6 : string = null
警告!
注意不要像在 C# 中那样对 in/out 参数使用 ref
关键字。例如,以下不会产生所需的结果:
let success7 = false
let result7 = o.GetValue (10, ref success7)
输出:
val success7 : bool = false
val result7 : string = "Ten"
为什么 success7
保持值 false
?因为 success7
是一个不可变变量。
在 C# 中,ref
提请注意您正在将对变量的引用作为参数传递给 ref
参数。它只是作为一种保证,即调用者的程序员知道该变量可能会被调用的方法修改。然而,在 F# 中,ref
创建一个新的引用单元格,其中包含 的副本 以下表达式的值。
在这种情况下,我们正在创建一个引用单元格,其中包含从 success7
变量复制的值,但不会将该新引用单元格分配给任何变量。然后我们将该引用单元格传递给 GetValue 方法,该方法修改引用单元格的内容。因为调用方法没有指向修改单元格的变量,所以它无法读取引用单元格的新值。
我认为这里还值得一提的是out参数的值不必初始化。
可以执行以下操作:
let mutable success3 = Unchecked.defaultof<bool>
let result3 = o.GetValue (10, &success3)
这在您使用数组作为输出参数调用 .NET 库函数的情况下可能很有用,即:
let mutable currFeatures = Unchecked.defaultof<PointF[]>
let mutable status = Unchecked.defaultof<byte[]>
let mutable trackError = Unchecked.defaultof<float32[]>
CvInvoke.CalcOpticalFlowPyrLK(
previousFrame,
nextFrame,
previousPoints,
Size(15,15),
2,
MCvTermCriteria(10, 0.03),
//Out params
&currFeatures,
&status,
&trackError,
//---------
LKFlowFlag.UserInitialFlow)