我正在尝试在 F# 中通过引用传递。在C#中,使用ref和out关键字非常容易,但在F#中似乎没那么简单。我刚刚读过这个:http://davefancher.com/2014/03/24/passing-arguments-by-reference-in-f/,建议使用参考单元格。 (我想这意味着 C# 中没有类似的 out 关键字,您不必初始化变量来传递它。)
但无论如何,我想知道这是否是 F# 中通过引用传递的最佳/唯一方法,以及这在函数式语言中是否是一个好主意。
编辑:
我很感兴趣,因为我刚刚意识到异常正在减慢我的代码速度。我正在发起一场消灭他们的十字军东征。基本上,我的计划是这样的:假设一个函数返回一个双精度值,或者如果出现错误则抛出异常。相反,我将通过引用传递一个 double 和一个 ErrorCode 类型作为位掩码,然后向下传递值和错误。我猜我只需要让所有这些变量都是可变的。
您的问题有很多部分,我会尽力回答:
建议使用参考单元
我想这意味着 C# 中没有类似的 out 关键字,您不必初始化变量来传递它。
out
参数来表示附加返回值。在 F# 中执行此操作的惯用方法是使用元组。例如,C# 函数 int TryParse(string s, out bool succeeded)
就是简单的 TryParse(s : string) -> (int, bool)
如果这对于函数式语言来说是个好主意的话。
type MyFunctionResult =
| Success of double
| ErrorCase1
| ErrorCase2 of AddditionalDataType
等等
如果您有许多使用此样式的函数,则非常容易将它们与
bind
函数组合在一起。
您可以使用
&
代替 C# 的 ref
,但以 &
为前缀的变量必须是可变的。一篇不错的文章,甚至涵盖了 PInvoke 陷阱:https://paul.blasuc.ci/posts/managing-pointers-or-pinvoke-gotcha.html.
open System.Collections.Generic
let dic = new Dictionary<string, string>()
dic.Add("key", "myvalue")
let mutable v = "" // v is mutable
let success = dic.TryGetValue("key", &v);
System.Console.WriteLine(v)
let succ, value = dic.TryGetValue("key") // this is what Mark Seemann says is the comment, a shortcut for C#'s `Try...(.., out ...)` is using tuples in F#
让我描述一下 OCaml 的作用,因为我不知道 F#,并且有人可以确认 F# 足够相似以至于我的答案适用。
在 OCaml 或 F# 等函数式编程语言中,数据默认是“不可变”的。也就是说,您需要在事物可变之前将其声明为可变的,事实上可变数据结构不如不可变数据结构常见(但并不罕见)。 现在,因为默认情况下数据是不可变的,所以如何传递参数并不重要,因为它们无论如何都不会改变。在这种情况下,传递简单的数据类型是有意义的,这些数据类型按值放入寄存器,而其他所有内容则按引用传递。
当然,可变数据类型是通过引用传递的,否则拥有它们就没有什么价值。
也许您可以给我们举一个您正在尝试做的事情的例子。您传递的是可变数据还是不可变数据?
obj ref
并且刚刚通过
obj
browser.Navigate2(url_obj)
所以我刚刚添加了
ref
并且它起作用了
browser.Navigate2(ref url_obj)
所以我想你只需添加
ref
。
在使用 COM 对象时非常有用。